-
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
Encapsulate serialization in ActiveModel::SerializableResource #954
Conversation
5b0a4c3
to
f2958c1
Compare
if builder.serializer? | ||
builder.serialization_scope ||= serialization_scope | ||
builder.serialization_scope_name = _serialization_scope | ||
adapter = builder.adapter |
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.
💯 right?
If this looks good, I'll update the README as well. There are other places the builder can (should?) be applied in the tests, but nothing that I thought was necessary for this PR. I didn't add explicit tests for the builder since it's essentially an extracted method object and is covered by existing tests. Eventually, some tests should be extracted/added to it. This PR moves us closer to 1) having a simple interface for building the adapter 2) using the simpler interface for testing serializers in our apps outside of the controller (e.g. some hacks I've written ) I think I'll add |
@@ -2,10 +2,12 @@ | |||
|
|||
module ActiveModel | |||
class Serializer | |||
Error = Class.new(StandardError) |
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 any particular reason to implement this Error
class across the PR?
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 added it so that I could raise an AMS-specific failure in the 'deprecated' controller methods, and there wasn't any Error class already defined. I wanted to make sure when testing, for example, that I'm asserting that I'm raising a Runtime error and that it actually is the one from the method, rather than an accident elsewhere in the code... I could check the exception message, I think.
@bf4 Thank you for your work on this. Summoning @kurko @guilleiguaran : ppl just to clarify. The idea here is to make it easier to use AMS outside controllers. Test scenarios or background jobs for example. Right now it's a kind messy have to instantiate the I made some pontual comments into the PR itself, but overall I liked the implementation, just worries about the deprecations and how it can impact other developers. Wanted to hear your thoughts about it 😄 |
For ease of review, I'm going to push changes as new commits, and rebase when done. |
extend ActiveSupport::Autoload | ||
autoload :Configuration | ||
autoload :ArraySerializer | ||
autoload :Adapter | ||
autoload :Builder |
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.
Now that I look at it, shouldn't we be moving away from autoload
to a thread safe world?
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.
autoload is threadsafe for some time now. See headius/thread_safe#15 (comment) and even if it weren't extend ActiveSupport::Autoload
would make it so.
81eb1f0
to
9144f39
Compare
scope_name = options[:scope_name] | ||
# Adds a class method with ':scope_name' that calls ':scope()' | ||
# But isn't called anywhere |
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 intend to include this comment in the final PR, but wanted to bring attention to scope/scope_name now being dead code, in case you'd like me to remove calling it from the controller and the builder.
8fd0467
to
7e29219
Compare
Moved functionationality from I think the current state is better than before. |
Per rails-api#954 (comment) Ref 917, 918
d2a4803
to
d2d8c28
Compare
Per rails-api#954 (comment) Ref 917, 918
Failure seems transient, related to global state issues present in master https://travis-ci.org/rails-api/active_model_serializers/jobs/68195121 Possibly related to #961 |
require "set" | ||
module ActiveModel | ||
class Serializer | ||
class Builder |
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.
So, I think this PR is a great step in organizing things. The current serializer is a huge mess.
With that said, I just want to leave registered in the interwebs a comment here about nomenclatures that we think we need to improve, if not in this PR, in the future. I think it's a bad idea to name objects/classes with anything ending in *er
because you'll end up with things like Builder#build
. SerializedHash#build
expresses much better its intent. I've written about it and more in http://alexsquest.com/texts/complexity-in-software-4-the-art-of-naming. There's also http://www.carlopescio.com/2011/04/your-coding-conventions-are-hurting-you.html.
Not a blocker, just something to improve, perhaps in another PR.
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.
Do you have a suggestion for a better name? I believe AMS used to have a build_as_json method, or something like that. I actually don't like builder all that much either, but honestly, I find the adapter being what we call serializable_hash on, rather than the serializer, more confusing, which is part of why I'd like to encapsulate their combined behavior.
(I'm actually thinking of collecting common class names from Ruby projects and seeing what works and what doesn't. This is of interest to me as well).
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 fact, I would name this class Serializer
if there weren't already one... ResponseSerializer
? FinalSerializer
? SerializableResource
?
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.
Renamed this to SerializableResource... could use some 👀
b69a0e1
to
5b354f5
Compare
Per rails-api#954 (comment) Ref 917, 918
5b354f5
to
80c9715
Compare
Per rails-api#954 (comment) Ref 917, 918
begin | ||
serialized = serializer.new(resource, @_serializer_opts) | ||
serializable_resource.adapter | ||
rescue ActiveModel::Serializer::ArraySerializer::NoSerializerError |
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 seem to be the right place or way to catch the failure when instantiating the serializer
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.
Baby steps 😁
@kurko @joaomdmoura How can I push this forward? |
# Deprecated | ||
def use_adapter? | ||
true | ||
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.
I think we could remove the method and the warning. Any specific reasons to keep it @bf4 ?
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.
Only because someone might have used it to turn off the adapter and hence skip the serializer
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.
hmmm, okay, lets just not forget of removing it after a while, maybe on official 0.10.x release, I'm not sure. tks 😄
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'm happy to add a self-destructing 'raise if AMS.version > 0.10.0' type of thing. That sorta what you're thinking about?
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.
If this is a blocker for you, I'd rather remove it, merge, and discuss in subsequent issues or PRs
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.
No, not a blocker! 😄 Let's keep it for now. Just wanted to hear @kurko opinion before I merge it because he was following it too
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 the meantime, would you like me to rebase the renamed builder -> serializable_resource?
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.
Baby steps. No need to cause so many changes in one PR. If you're refactoring, try to avoid change of behaviors in the same go.
LGTM @kurko ? |
}.new | ||
assert_match /adapter: false/, (capture(:stderr) { | ||
controller.get_serializer(@profile) | ||
}) |
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.
here's the test for when someone has defined use_adapter?
as false
I think it cleans a lot of things and it's good. I think there's more work to be done, specially because it was really hard to understand all the changes without a lot of mental effort. This is a good step. |
@kurko Can you help me get to what would you like to see? Just copy the controller logic into a method on SerializableResource? Tell me what you like this to look like and I'll make it so (and then some followup prs) |
Usage: ActiveModel::SerializableResource.serialize(resource, options)
Per rails-api#954 (comment) Ref 917, 918
80c9715
to
df14029
Compare
@kurko @joaomdmoura Any blockers on this? Any more discussion needed? Any changes to make? I've updated the PR description a bit (could probably be better written). |
@bf4 I've read through the thread again and checked the code. |
Encapsulate serialization in ActiveModel::SerializableResource
Yay! |
Per rails-api#954 (comment) Ref 917, 918
Usage:
ActiveModel::SerializableResource.serialize(resource, options)
tl;dr as seen in test/serializable_resource_test.rb
ActiveModel::SerializableResource.new(@resource)
can now be tested outside of a controller instead of the (more or less) equivalent codeActiveModel::Serializer::Adapter.create(ProfileSerializer.new(@resource))
ref: discussion in #936 (diff)
This PR includes
get_serializer
controller method which may possibly better extensibility, and possibly better compatibility with Rails serializer proposal in https://groups.google.com/d/topic/rubyonrails-core/K8t4-DZ_DkQ/discussionuse_adapter?
and displays a warning when falsy.ActiveModel::SerializableResource.serialize
method which implies WIP - Deserializer implementation #950 may add the interfaceActiveModel::SerializableResource.deserialize