-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Add inline syntax to override attributes/associations. #1262
Conversation
Nice notion! But it increases complexity for a solved problem. If you want to prove the problem isn't solved, and this fixes it, use attributes named 'test' and 'select' that fail before the change and work after. i.e attribute :select
def select
object.banana
end vs.
|
@bf4 You're right, in the current state of things, this does not solve the aforementioned problem. However, in order to solve it, we need to get rid of users defining a virtual/overridden attribute as a method on the serializer, which this PR offers a way to. |
I still don't see how this helps in any way. Show me! ;) B mobile phone
|
Well, I still want to hold on this B mobile phone
|
@bf4 Sure, let's talk about it when you're back. |
end | ||
|
||
def test_virtual_attribute_block | ||
post = PostWithVirtualAttribute.new(first_name: 'Lucas', last_name: 'Hosseini') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in this case, you might want to test post.attributes
since that's the immediate case.. tests less layers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to see this too.
end | ||
end | ||
|
||
def attribute(attr, options = {}, &block) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the &block
param.
I'm still very 👎 on this. Sorry. If you weren't a collaborator I would close it. |
@bf4 Any specific reason? |
I don't think it's good for AMS. |
Would you care to give
|
Because as you can imagine, I do think it's good for AMS, so it's kind of a Mexican standoff. |
except others are welcome to show up and approve :)
|
_attributes << key unless _attributes.include?(key) | ||
|
||
ActiveModelSerializers.silence_warnings do | ||
define_method key do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this absolutely needs to be document above the method signature with some examples.
I am a HUUUGE fan of metaprogramming, but it can be a pain in the butt if people aren't expecting it. So, having some example syntax in a method yardoc would be fabulous.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, although this code is already in AMS. I just added the if block_given?; ...; else
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Never hurts to add documentation. Code pre-existing isn't an excuse to not add docs. :-\
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, as I said, I agree. I was just making clear that I didn't just throw loads of metaprogramming magic without comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh :-) 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- we should be conservative in adding new interfaces because then we need to support it
- if we need this feaure, why? If we don't need it, what are the trade offs of adding it? Not adding it?
- how does it affect ease of understand usage? Ease of maintenaince? Complexity of either?
- is it extending existing behavior or modifying it? Could it bd done another way?
- how do you see this feature evolving? What are its limitations? Can it be easily customized? Eg adapter no longer need to be in thd ams namespace or even inherit the base. So, it's easy to extend (though the boundaries could be clearer and the interfaces more consitent. Am::s should probably be called a resource and implement the serializers::json interface
(Writing in phone; apologies for anything unclear)
ok, so -- I am a fan of, especially for the json api, how there are numerous things that can be configured via blocks. I think that's very consistent, and doesn't leave our users guessing as to which syntax to use. I do agree that the way module inheritance has been going has been kinda sketchy, but I believe that is a bigger overall architecture discussion for another time. @beauby, you have my 👍 @bf4, do have any specific concerns about this for AMS? I do know some static analysis tools will complain if there is too much code at the class level, and prefer things to be done in methods (as they are more easily testable, stubbable, greppable etc) |
@bf4:
I agree. We should also provide the best possible interfaces to our users.
This feature has two main benefits:
As stated above, I believe it improves ease of usage. Complexity and ease of maintenance are hardly increased.
Currently, it is extending existing behavior. It could be done in an other way.
I'm not sure about what you mean by evolving, limitations and customization in this setting.
Not sure I understand. This PR does not deal with adapters in any way.
Sounds sensible
The |
like I said, it's pretty similar, but I don't like passing the block all over the place. I'd like a more surgical change. |
Also, what I described solves a problem. It's more than just sugar |
@bf4 As I stated in the PR description, this is only part 1 of a 2 part PR:
Plus, at the end of the day, this PR is passing a proc around, not a block. |
So to sum up my vision of things here:
|
I'm not sure I understand the significance of the distinction. I don't follow. It's a callable object. Proc, Lambda, Method are all objects that are all callable. |
You said
I said
|
In any case, I think the change in this PR could be much smaller, solve the problem ( no need for #1263 ), and actually improve the design and clarity of the code, as I discussed in #1262 (comment) Still needs work, IMHO. Let's focus this PR on defining/encapsulating attribute conversions at the class level. Let me know if you want to pair. |
Where are we on this? want me to submit a PR to your branch? |
Will update soon. |
awesomes |
@bf4 See 1311 which covers half of this PR (the associations part). |
class << base | ||
attr_accessor :_reflections | ||
end | ||
base.class_attribute :_reflections |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
did you intend to allow instance reader/writers? did you intend to make it inheritable?
Closed by #1356 |
This PR brings the following syntax for overriding attributes/associations and declaring virtual attributes/associations in a serializer:
that is currently equivalent to the usual
Note that this change is not only cosmetic, as it is a prerequisite to move away from the old way (defining methods on the serializer, which caused many issues when the attribute name was that of a reserved method name (ref #1261)), and refactor the way attributes are handled in a safer way.
Update: added overriding of associations as well + factoring out of the attributes logic.