-
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 a #to_json method to the serializer base #889
Add a #to_json method to the serializer base #889
Conversation
Can we put this on hold? I'm 99% sure this is the wrong solution, but I just got back from RailsConf so I need to catch up on the original issue |
TL;DR if you are using Rails you should never and never have to define to_json and should define as_json instead |
Indeed, found some resources that points exactly towards that direction. We should probably call this method instead of to_json def as_json
self.class.adapter.new(self).as_json
end @chancancode any thoughts on it? |
(Without knowing how any of the current AMS stuff works) that sounds about right! |
@guilleiguaran as I know you were the last one updating |
I agree with @chancancode, if we're adding a method it should be |
Cool! @JustinAiken could you please update the implementation to match the convention? 😄 |
db487a3
to
32c5fa9
Compare
Rebased |
@@ -177,6 +177,10 @@ def json_key | |||
end | |||
end | |||
|
|||
def as_json | |||
self.class.adapter.new(self).to_json |
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.
Also update the adapter call to use as_json
method
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.
Oops sorry, reading fail. Rebased again.
32c5fa9
to
09f3362
Compare
Ok, this is good, but I'm thinking something else. Should we default to json_api adapter so this would never be an issue? |
@@ -177,6 +177,10 @@ def json_key | |||
end | |||
end | |||
|
|||
def as_json | |||
self.class.adapter.new(self).as_json |
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.
Should this be:
def as_json(options = {})
ActiveModel::Serializer::Adapter.create(self, options).as_json(options)
end
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.
@ryansch .create
calls .new
behind the scenes
The difference here would be if you want to set the adapter through options.
IMO it's safe to assume that the adapter can be presumed.
btw if it was .create
it would need to pass the resource instead of self
If there is a specific reason that I'm haven't seen, just let me know! 😄
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 doesn't make sense to me, feature wise. You should never be calling to_json/as_json on a serializer. The serializer's job is to serialize the resource. The adapter formats the serialized resource per json/json-api whatever, and is the actual object that gets to_json/as_json called on it.
I'm 👎 on this unless I'm totally misunderstanding something. See http://www.benjaminfleischer.com/2015/06/02/understanding-rails-model-serializers/
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.
As we discussed earlier #889 (comment) #889 (comment) and in #936 (comment) I think the real issue is that the the code in the actioncontroller::serializer that wraps the model to be rendered in the adapter needs to be encapsulated as 'the way' a resource is serialized in one nice step. I'm intended on making that PR sometime in the next week. cc @chancancode
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.
@bf4 I partially agree with u on this.
The goal here is to make it simpler to use AMS on tests and outside controllers in general.
Indeed the implementation at your comment is clean but not as easy as as_json
.
In the other hand, the PR that you mentioned might provide another solution, so I'm leaving this open some more days for now.
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.
Interesting. Well that certainly makes sense. I think associations use an adapter, though... Is that a problem for serializing an object snd posting in a request?
B mobile phone
On Jun 12, 2015, at 4:23 PM, Ryan Schlesinger [email protected] wrote:
In lib/active_model/serializer.rb:
@@ -177,6 +177,10 @@ def json_key
end
end
- def as_json
Agreed. We also use serializers to talk to Elasticsearch outside of a controller.self.class.adapter.new(self).as_json
—
Reply to this email directly or view it on GitHub.
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.
Sorry, I lost context of the change we were talking about.
class Serializer
+ def as_json
+ self.class.adapter.new(self).as_json
I agree it would be good to have a single simple way to serialize a resource, but I think this specific change, as simple as it is, sweeps the problem under the rug. While, I myself was at first surprised that I couldn't call as_json on a Serializer, the fact is, as the diff highlights, we don't. We call it on the adapter. So, adding an instance method to a serializer that creates an adapter and then calls as_json, is, I think, problematic because it introduces more places where the code is responsible for knowing to pass the serializer instance into a new adapter then call as_json on the resulting adapter instance. As much as I really like the idea word-wise, as the code stands, I think it actually adds more complexity.
That said, if we merge something like #954 (disclaimer, I'm writing it), where we have a single place where serialization happens, then we could add this method as
def as_json(json_options = {})
ActiveModel::Serializer.build(object, options.merge(serializer: self)).as_json(json_options) # pseudo-code
def to_json
ActiveModel::Serializer.build(object, options.merge(serializer: self)).to_json # pseudo-coe
Then we could have the convenience of BlogSerializer.new(blog).to_json and maintain the single place in the code of knowing how to combine the object, serializer, adapter, and options. (though it would still lose the ability to pass in any adapter options and still keep the as_json interface unless we start deleting keys... etc)
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.
Sounds good to me... as a regular user of AMS, all I care is that I -can- call #as_json
or #to_json
, not what happens behind the curtains to enable it 😀
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.
@JustinAiken I'm interested in your thoughts on #954 from a usability perspective ( And I we can update and move #967 into the wiki, as @joaomdmoura would prefer )
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.
The part of #954 that applies to my need (I just want #as_json
or #to_json
, hahahaha) looks great to me 👍
.. I don't have much to say on the rest of the changes - I'll let people more familiar with AMS's inner workings and roadmap provide more informed opinions on the rest.
To be clear, we use serializers in other places than just |
@ryansch if you need to render whatnot manually, just follow these (easy?) steps (I'm using resource to be what is usually an active record model, but is anything that includes activemodel::serializer serializer = ActiveModel::Serializer.serializer_for(resource)
serializer_opts = { each_serializer: serializer }
serializer_instance = serializer.new(resource, serializer_opts)
adapter_opts = {root: "items", adapter: "json"}
adapter = ActiveModel::Serializer::Adapter.create(serializer_instance, adapter_opts)
adapter.as_json I described this with some more general code in #878 (comment) |
Oh I agree. We're already doing this in a bunch of places in our project. That repetition made me feel like it needed a proper abstraction. |
@JustinAiken could you rebase this with master? 😄 |
09f3362
to
3315b01
Compare
^^ Rebased ^^ EDIT - Uh-oh, spec failure on rubinex... will poke at today.. |
haha no worries @JustinAiken. |
hey @JustinAiken and @ryansch, have you guys check #954 ? |
Just read through all this 👍 Appreciate both points of view but |
@daino3 I honestly think it might be better to add the methods and have them raise an exception saying one should be using the adapter |
@bf4 - I understand your PoV. But I think a lot of folks will monkey patch a helper method in anyway - so why not just build it in? I'll give you a pretty common use case: Rails + Angular - rendering html from a rails controller, but instantiating some json variables in the rails controller to hand them off to angular in the view (for hybrid apps that aren't purely single-page apps). So I wouldn't want to repeat myself with a long-winded way to call |
Only because from the point of view of the library, the serializer is not the thing you're serializing, and I think adding those methods only adds to that confusion in naming. If I didn't know the internals, I'd totally agree with you. Which is why I'm hope #954 get's merged so that the answer becomes ActiveModel::SerializableResource.serialize(post).to_json I wrote more above in #889 (comment) |
👍 Well, you guys got some decisions to make 😄 . But rc2 looks great. Thanks for all the work you guys do! |
@daino3 (would |
OK. I just looked through the PR. Here are my thoughts - and please take this with a grain of salt -> you guys definitely know that codebase so much more than I do after me digging through for just a couple hours.
Therefore, I would cast my vote towards the simpler helper method on the serializer class. |
@daino3 Thanks for your thoughts. (n.b. read this while smiling and laughing to yourself) You know, the funny thing is, my (personal) resistance to this pr is also "mo code, mo problems..." since it make multiple parts of the library responsible for knowing how to serializer a resource. Now, that said, if #954 were merged and this PR changed to call the SerializableResource under the hood, there'd be no SRP violation, just the semantic issue, which doesn't bother me as much since I find the naming confusing as well. |
👍 to both of you @bf4 and @daino3 |
#954 is now merged. Is there still interest in this PR? |
Looks like #954 will take care of me at least... |
@JustinAiken It's your PR if you want to close it... |
As proposed in #878
Let me know if you think the test would fit better somewhere else and I'm move it and rebase.