Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Let decorator_class infer anonymous class' decorator from superclass #820

Conversation

masolin
Copy link
Contributor

@masolin masolin commented Sep 5, 2017

Description

Since Rails 5, draper gem gets some issues of raising NameError on inferring decorator class (#773). The previous PR (#795) fixes this issue when using decorate_collection, but this issue can also happen when using decorate, and we encountered this issue on our production code when upgrading to Rails 5.

I tried to replace constantize with safe_constantize in this PR, so we don't need to rescue and check if the NameError was caused by draper itself anymore. It should be safer than previous approach.

Thanks.

References

@codebycliff
Copy link
Collaborator

@masolin Thanks for the contribution! I think this change makes sense, but give me a little bit to think through any unintended side affects. Also, if we do move forward with this, I think it would make sense to update all the other usages of constantize to use safe_constantize as well.

@steveklabnik @jcasimir This change makes sense to me, but wanted to double check with one of you guys in case there is some historical knowledge I'm missing.

@steveklabnik
Copy link
Member

It's been too long; I don't remember any details here, sorry!

@masolin
Copy link
Contributor Author

masolin commented Sep 6, 2017

@codebycliff Please let me know if you think that it's ok to use safe_constantize. I will change the other part as well. Thanks.

@codebycliff
Copy link
Collaborator

@masolin Thanks for your patience on this. I'm good with this change. If you can get the other uses of constantize updated to use safe_constantize we can get this merged. Thanks again!

To prevent rescuing and checking if NameError is from internal decorator
private methods, we change to return nil on these private methods.
@masolin
Copy link
Contributor Author

masolin commented Sep 12, 2017

Hi @codebycliff
I replaced constantize with safe_constantize on most of the parts except for self.decorates, because it's a public method and makes sense to return NameError.
In addition, I also revised a private method, object_class_name, to return nil rather than NameError, so we don't need to rescue and check if NameError is from draper gem anymore.

Please help to review it. Thanks.

Copy link
Collaborator

@codebycliff codebycliff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made a few review comments. They are mostly style / consistency suggestions. Let me know what you think or if you have any better ideas. Thanks again!

name_constant = name && name.safe_constantize
raise Draper::UninferrableObjectError.new(self) if name_constant.nil?

name_constant
Copy link
Collaborator

@codebycliff codebycliff Sep 13, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Decoratable#decorator_class above, you are returning the constant unless it's nil and raise at the end. Here you are doing the exact opposite. For consistency purposes, I think it would make sense to follow the logic from above here as well:

name_constant = name && name.safe_constantize
return name_constant unless name_constant.nil?
raise Draper::UninferrableObjectError.new(self)

singular = object_class_name
plural = singular && singular.pluralize

plural == singular ? nil : "#{plural}Decorator"
Copy link
Collaborator

@codebycliff codebycliff Sep 13, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While the ternary statement works just fine, returning nil is the default behavior. So it might read better to say:

singular = object_class_name
plural = singular && singular.pluralize
"#{plural}Decorator" unless plural == singular

What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel that the ternary statement can make me more easily realize the 2 possible return types: nil and "#{plural}Decorator", but I don't have strong opinion on it, so it's fine to change

"#{plural}Decorator" unless plural == singular

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My opinion isn't strong either. I see the advantages of the ternary as well. Completely up to you.

@drapergem drapergem deleted a comment from masolin Sep 14, 2017
Copy link
Collaborator

@codebycliff codebycliff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks again! I'll try and get a release out in the next week or so.

@masolin
Copy link
Contributor Author

masolin commented Sep 14, 2017

Thanks a lot. 😄

@codebycliff codebycliff merged commit cc23669 into drapergem:master Sep 14, 2017
@codebycliff codebycliff added this to the 3.0.1 milestone Oct 12, 2017
@codebycliff
Copy link
Collaborator

This has been released to RubyGems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants