-
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
Deprecate ActiveModelSerializers::Model #1911
Conversation
@richmolj, thanks for your PR! By analyzing the annotation information on this pull request, we identified @bf4, @yevhene and @NullVoxPopuli to be potential reviewers |
@@ -59,4 +59,6 @@ Gem::Specification.new do |spec| | |||
spec.add_development_dependency 'grape', ['>= 0.13', '< 1.0'] | |||
spec.add_development_dependency 'json_schema' | |||
spec.add_development_dependency 'rake', ['>= 10.0', '< 12.0'] | |||
spec.add_development_dependency 'pry-byebug' | |||
spec.add_development_dependency 'm' |
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 don't like putting anything in the gemspec not required for running the tests. I'd rather this be proposed to the Gemfile in a separate PR. Since this has come up a couple of times and I basically have the same thing in my Gemfile.local
I think it's worth adding
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.
re: deprecation, we can easily extract all the behavior to a mixin... I'm not sure I want to deprecate, since it's just a convenience implementation of the interface. |
object.send(attr) | ||
else | ||
# Special logic for hashes | ||
if object.is_a?(Hash) |
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.
👎
For most of the comments: agreed, all good - this is mostly just scratchpad stuff I pushed so we could talk about the deprecation notion itself. If we decide to deprecate vs. turn into a module vs. just make the accessor tests pass, I'll submit a new PR. |
Regarding But after that, maybe someone could explain the point of the contract to me. I understand what it is, I just don't know why it's part of this gem...this gem doesn't use most of that functionality AFAIK. For instance, why do we care how the object to be serialized was initialized? As far as I can tell the only required contract is |
By the way, the reason this started coming up is because our new # Assume everything else about child is ActiveModel compliant
class Child
def initialize(parent, attributes: {})
@parent = parent
@attributes = attributes
end
end If we did:
We've now
|
I don't think you'd have to override the constructor. The only thing the constructor has done for AMS::Model, is that it sets default / starting attributes on the model. Since attribute tracking/storage is inevitably up to the implementation, we could just forgo that "feature" of the barebones module. |
@NullVoxPopuli yes, we both had the same thought 😄 The problem is the constructor sets def read_attribute_for_serialization(key)
if key == :id || key == 'id'
attributes.fetch(key) { id }
else
attributes[key]
end
end So if we remove the constructor the rest of the
So this is my thinking as well. What features would a barebones module provide? And as far as I can tell, the only required feature is: alias :read_attribute_for_serialization, :send If that's the only thing our barebones module would need, why not just handle that in a conditional within the code instead of requiring clients to implement it? Then our only contract is if you define |
Even though I think time could better be spent elsewhere, I think this should be done more incrementally, rather than a whole bunch of controversial changes all at once. |
@NullVoxPopuli I agree a real PR should be done more incrementally, this was just a WIP to get a discussion going. I kind of regret doing a PR instead of an issue since I think that is a source of confusion.
I can see why you would think that is what this PR is trying to do, since it really has one foot in 'make it a mixin' and one foot in 'deprecate it'. However, that's not my intent. I am not trying to make AMS::Model flexible. I am pointing out that it is not needed at all.
My point is, if we did this, |
@richmolj do you think you have the time / desire to split everything up? |
@NullVoxPopuli I think so, it's actually mostly changing the test POROs more than anything else. But I want to make sure we all agree on the gameplan / that this makes sense before I take on that work. My suggested plan is here. |
I think that's the right track, yeah. Though, I don't think it's stated that Though, I wonder if these should be namespaced further?
|
@NullVoxPopuli agree on the namespacing but
I'm not sure this module is even needed at all. What do you foresee the problems being? |
Well, something needs to implement read_attribute_for_serilaization. |
Not if we change if object.respond_to?(:read_attribute_for_serialization)
object.read_attribute_for_serialization(key)
else
object.send(key)
end |
I'm conflicted on that. I think for now, to maintain existing functionality, we should have a small module that implements read_attribute_for_serialization via send. (which, I know is the same thing), but I don't think we should force everyone to use |
In the above code, Anyway, I still prefer the serializer.rb change but I can get behind this 👍 |
we can make AMS::Model deprecated and split it in to 3 modules without controversial changes :-) I just think forcing |
But our module would make |
not so. serializer.rb is used everywhere. the model is only used by non AR people. :-\ |
everywhere == activerecord right? activerecord already implements read_attribute_for_serialization, so |
In fact, it internally just calls send O_o |
lol. Well I've been defeated! I guess go ahead and PR away. haha |
😆 @bf4 you agree with this plan? If so I can get cracking on PRs. |
I haven't read everything so bear with me: read_attribute_for_serialization was born in Rails before AMS was removed Linting was added to clarify the api of reaources that AMS expects Linting was based on ActiveModel::Lint ActivrModel::Lint gave birth to ActiveModel::Model. AMS::Model was born as PORO documentation and for convenience I use AMS::Model myself So, everything is need driven I only never separated minimal linting from comprehensive Initializers have nothing to do with the interface AMS expects of arguments to its serializers AMS::Model is executable documentation, not a requirement |
@richmolj can you clarify the plan? The tl;dr is that it is a huge change if AMS no longer expects objects to either include |
@bf4 sure, let me try and separate the why and the how here. I'm more than happy to be in the wrong here due to some missing context, I'm just not sure what that context is. Why
HowI think five main steps:
Does this make sense? |
Thanks for writing that all up. Do I understand that you'd prefer the only requirement for input serializer is respond_to? and send? Just for context, you've looked at why read_attribute_for_serialization was introduced, what it's for, how it's used in Rails, and that AMS uses activemodel because it came from activemodel and complements it? Given our discussion, am I correct that better docs would explain PORO usage better? More later when I'm not thumb typing an email while putting the kids to sleep :) |
@bf4 let me try a silly analogy. Let's say we had a dog, but we named it 'cat' and fed it cat food, gave it a litter box, everything. And this issue is akin to saying, "let's stop treating our dog like a cat." Let's get rid of the litter box, throw away the balls of yarn; they are not needed. And sure you could view that as a major change...but fundamentally it's always been a dog; nothing is really changing. That may have only made sense to me 😆 Let me answer your specific questions:
My point is that's currently the only requirement. We currently require users to alias
As I said at the top of my last comment, I would love to get additional context showing the flaw of my logic. I could absolutely be missing something and would appreciate getting the additional puzzle pieces filled in. I've been going off of commits and comments, the comment for
OK, so
This is just speculation, but my guess is there used to be tighter coupling between this library and activemodel. But over time they have become decoupled. Let's stop treating them like they are still coupled (let's stop treating our dog like a cat).
To an extent, maybe? I think the better docs would be something along the lines of "ignore ActiveModelSerializers::Model and add this alias". And if those were the docs I'd ask why we don't just help our users by implementing Once again, I am totally open to getting some missing context. Barring that, all I can do is follow logical reasoning and make a proposal based on that reasoning. |
@richmolj I've been thinking about this off and on. Basically, changing the serializable interface is a huge breaking change in the code and philosophy of AMS. It should really be an RFC before it is a PR. In addition, I'd rather we spend time on critical issues within AMS before re-architecting it. As Kent Beck has said
|
It's not a breaking change at all, much less a huge breaking change. And per Mr. Beck, it's also already an easy change. If those statements are false, please let me know why, I would love to improve my understanding. I really would love to get an actual response with some sort of counterargument or technical reasoning. I've said in this thread I regret making this a PR, I only wanted to share how I fixed the tests you wanted fixed and to share a solution on how to make this a mixin (since this was harder than I thought it would be). At this point I don't even have enough information to write better documentation, since no actual technical arguments are being made and no additional context is being supplied. I will move this to an RFC in hopes of getting a better discussion. |
@richmolj looks like only a new PR will resolve all the concerns :-) |
New RFC! #1926 |
Purpose
Deprecate
ActiveModelSerializers::Model
. We don't need it. We can easily support PORO serialization without this class, whether it be a superclass or rewritten as a mixin.The docs make it seem like we're providing the ability to do PORO serialization. We're actually providing more functionality than we need to do this.
Minimum requirement we need:
But this ActiveModelSerializers::Model provides extra stuff like
So these are really solving two problems:
#attributes
, etc).While the latter is nice to have in tests and such, it's not really required by this gem AFAIK. I'd say it should be out of scope, actually, and better handled by a separate library like Virtus.
In other words, we're linting that we quack like more of a duck than we really need to quack like.
This PR attempts to allow serializing POROs out of the box, with no extra superclass or mixin required.
Changes
This PR is a WIP but I think the meat of the change is altering
read_attribute_for_serialization
:You can now serialize any PORO, including ruby hashes, with no extra code.
The other changes in this PR are mostly related to reorganizing
ActiveModelSerializers::Model
(this intended to convert it to a mixin). I suggest we end up not making these changes and instead write a deprecation any timeActiveModelSerializer::Model
is extended or initialized.Caveats
One issue is with the current tests, which currently use
ActiveModelSerializer::Model
for POROs. In particular heavy use of the constructor. We would probably want to rearrange the tests so they keep this behavior but inherit from some internal test class instead.Related GitHub issues
#1877
#1283
#1873
Additional helpful information
This code is not ready to be merged. It's what I have working and available for discussion. If we can reach consensus I'll flesh it out.