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

Encapsulate serialization in ActiveModel::SerializableResource #954

Merged
merged 2 commits into from
Jul 31, 2015

Conversation

bf4
Copy link
Member

@bf4 bf4 commented Jun 12, 2015

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 code ActiveModel::Serializer::Adapter.create(ProfileSerializer.new(@resource))

ref: discussion in #936 (diff)

This PR includes

  1. a simple interface for building the adapter
  2. a simpler interface for serializing a resource outside of a controller for e.g. testing, background jobs, etc.
  3. the SerializableResource has all the expected methods: as_json/to_json/serializable_hash
  4. Uses the 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/discussion
  5. Deprecates the controller method use_adapter? and displays a warning when falsy.
  6. Deprecates calling ActionController::Serialization::ADAPTER_OPTION_KEYS in favor of ActiveModel::SerializableResource::ADAPTER_OPTION_KEYS
  7. Provides a ActiveModel::SerializableResource.serialize method which implies WIP - Deserializer implementation #950 may add the interface ActiveModel::SerializableResource.deserialize

@bf4 bf4 force-pushed the encapsulate_serialization branch from 5b0a4c3 to f2958c1 Compare June 12, 2015 18:24
if builder.serializer?
builder.serialization_scope ||= serialization_scope
builder.serialization_scope_name = _serialization_scope
adapter = builder.adapter
Copy link
Member Author

Choose a reason for hiding this comment

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

💯 right?

@bf4
Copy link
Member Author

bf4 commented Jun 12, 2015

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 #to_json/#as_json convenience methods to the builder that delegate to the adapter.

@@ -2,10 +2,12 @@

module ActiveModel
class Serializer
Error = Class.new(StandardError)
Copy link
Member

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?

Copy link
Member Author

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.

@joaomdmoura
Copy link
Member

@bf4 Thank you for your work on this.
I liked the implementation itself, but so many deprecations 😢
As we are on RC1 I think we could merge it, but first I would like to hear thoughts of other AMS members.

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 serializer, the adapter and then call .as_json into it.

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 😄

@joaomdmoura joaomdmoura added this to the 0.10 milestone Jun 13, 2015
@bf4
Copy link
Member Author

bf4 commented Jun 14, 2015

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
Copy link
Member

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?

Copy link
Member Author

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.

@bf4 bf4 force-pushed the encapsulate_serialization branch from 81eb1f0 to 9144f39 Compare June 16, 2015 17:22
scope_name = options[:scope_name]
# Adds a class method with ':scope_name' that calls ':scope()'
# But isn't called anywhere
Copy link
Member Author

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.

@bf4
Copy link
Member Author

bf4 commented Jun 21, 2015

Moved functionationality from render_with to get_serializer both for less deprecations, possibly better extensibility, and possibly better compatibility with Rails serializer proposal in https://groups.google.com/d/topic/rubyonrails-core/K8t4-DZ_DkQ/discussion

I think the current state is better than before.

bf4 added a commit to bf4/active_model_serializers that referenced this pull request Jun 21, 2015
@bf4 bf4 force-pushed the encapsulate_serialization branch from d2a4803 to d2d8c28 Compare June 21, 2015 04:46
bf4 added a commit to bf4/active_model_serializers that referenced this pull request Jun 21, 2015
@bf4
Copy link
Member Author

bf4 commented Jun 24, 2015

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
Copy link
Member

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.

Copy link
Member Author

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).

Copy link
Member Author

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?

Copy link
Member Author

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 👀

@bf4 bf4 changed the title Encapsulate serialization in ActiveModel::Serializer::Builder Encapsulate serialization in ActiveModel::SerializableResource Jun 25, 2015
@bf4 bf4 force-pushed the encapsulate_serialization branch from b69a0e1 to 5b354f5 Compare June 26, 2015 03:56
bf4 added a commit to bf4/active_model_serializers that referenced this pull request Jun 26, 2015
@bf4 bf4 force-pushed the encapsulate_serialization branch from 5b354f5 to 80c9715 Compare June 26, 2015 19:57
bf4 added a commit to bf4/active_model_serializers that referenced this pull request Jun 26, 2015
begin
serialized = serializer.new(resource, @_serializer_opts)
serializable_resource.adapter
rescue ActiveModel::Serializer::ArraySerializer::NoSerializerError
Copy link
Member Author

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

Copy link
Member

Choose a reason for hiding this comment

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

Baby steps 😁

@bf4
Copy link
Member Author

bf4 commented Jul 7, 2015

@kurko @joaomdmoura How can I push this forward?

# Deprecated
def use_adapter?
true
end
Copy link
Member

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 ?

Copy link
Member Author

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

Copy link
Member

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 😄

Copy link
Member Author

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?

Copy link
Member Author

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

Copy link
Member

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

Copy link
Member Author

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?

Copy link
Member

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.

@joaomdmoura
Copy link
Member

LGTM @kurko ?

}.new
assert_match /adapter: false/, (capture(:stderr) {
controller.get_serializer(@profile)
})
Copy link
Member Author

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

@kurko
Copy link
Member

kurko commented Jul 12, 2015

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.

@bf4
Copy link
Member Author

bf4 commented Jul 12, 2015

@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)

bf4 added 2 commits July 23, 2015 11:05
Usage: ActiveModel::SerializableResource.serialize(resource, options)
@bf4 bf4 force-pushed the encapsulate_serialization branch from 80c9715 to df14029 Compare July 23, 2015 16:07
@bf4
Copy link
Member Author

bf4 commented Jul 23, 2015

@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).

@joaomdmoura
Copy link
Member

@bf4 I've read through the thread again and checked the code.
It seems we don't have anything blocking this, and last inputs were positive. It will probably implies in some refactoring for me at #950, but I'm looking forward to it.
After reading it all seems that we have nothing to keep us form merge it, so I'm doing it.

joaomdmoura added a commit that referenced this pull request Jul 31, 2015
Encapsulate serialization in ActiveModel::SerializableResource
@joaomdmoura joaomdmoura merged commit b781265 into rails-api:master Jul 31, 2015
@bf4
Copy link
Member Author

bf4 commented Jul 31, 2015

Yay!

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

Successfully merging this pull request may close these issues.

3 participants