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

Add support for nested serializers #1225

Merged
merged 1 commit into from
Oct 9, 2015

Conversation

beauby
Copy link
Contributor

@beauby beauby commented Oct 2, 2015

This is half of #1193. This PR brings lookup for serializer classes in different namespaces (namely that of the parent serializer, that of the resource), so that the following is possible:

class PostSerializer < AMS
  has_many :comments
  class CommentSerializer < AMS
    ...
  end
end

(this is a way to make single-purpose nested serializers contained in one class instead of polluting the global namespace and having to call them PostCommentSerializer).

Cases not handled yet:

  • looking up for a serializer in the root namespace of a chain of serializers (post has_many comments belongs_to author: when a Post is serialized with a Namespace::PostSerializer, we might want to look for Namespace::AuthorSerializer),
  • looking up for a serializer in the controller's namespace (when Namespace::PostController serializes a Post, we might want to look for Namespace::PostSerializer).

@beauby beauby force-pushed the nested-serializer-lookup branch 3 times, most recently from 450744a to 9da2061 Compare October 2, 2015 14:44
@beauby beauby changed the title Add support for nested and namespaced serializers [WIP] Add support for nested and namespaced serializers Oct 2, 2015
@beauby beauby changed the title [WIP] Add support for nested and namespaced serializers Add support for nested and namespaced serializers Oct 2, 2015
@@ -112,10 +112,25 @@ def self.digest_caller_file(caller_line)
Digest::MD5.hexdigest(serializer_file_contents)
end

# TODO(beauby): Cache this.
def self.serializer_lookup_chain_for(klass)
Copy link
Contributor

Choose a reason for hiding this comment

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

I like this extraction.

Copy link
Contributor

Choose a reason for hiding this comment

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

some documentation on how this works (when to use, expected input/output, etc) would be fantabulous

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looks pretty much self-explanatory to me. What kind of comment would you add that would not be direct paraphrasing of the code?

Copy link
Contributor

Choose a reason for hiding this comment

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

me too, but I would like to prefer to over document than to under document. Like, look at how rails documents everything with plenty of examples: https://github.com/rails/rails/blob/master/activemodel/lib/active_model/errors.rb

Copy link
Contributor

Choose a reason for hiding this comment

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

(I guess that is more or less direct paraphrasing in some cases though) :-\

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah but serializer_lookup_chain_for is part of the private API.

Copy link
Contributor

Choose a reason for hiding this comment

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

fair point

Copy link
Member

Choose a reason for hiding this comment

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

@beauby beauby force-pushed the nested-serializer-lookup branch 2 times, most recently from b47d5e7 to 745cd82 Compare October 2, 2015 17:15
def test_serializer_for_nested_resource
comment = ResourceNamespace::Comment.new
serializer = ResourceNamespace::PostSerializer.serializer_for(comment)
assert_equal(ResourceNamespace::PostSerializer::CommentSerializer, serializer)
Copy link
Member

Choose a reason for hiding this comment

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

what's missing from the tests is when ResourceNamespace::PostSerializer.serializer_for is called. the tests don't confirm this is hooked up anywhere

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't understand. ResourceNamespace::PostSerializer.serializer_for is called just above?

Copy link
Member

Choose a reason for hiding this comment

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

What I see is:

ActiveModel::Serializer.serializer_for(post) #=> ResourceNamespace::PostSerializer
ResourceNamespace::PostSerializer.serializer_for(comment) #=> ResourceNamespace::PostSerializer::CommentSerializer

which tests serialization from an AM::S subclass, but not that the subclass is ever used.. maybe my comment just means there should be another test somewhere else

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Got it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We need to add a test to test/serializers/associations_test.rb to make sure the corresponding serializer gets used. This will be doable in a decent way once the test infrastructure refactor has been done.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added tests.

@bf4
Copy link
Member

bf4 commented Oct 2, 2015

Nice and slim! good encapsulation!

chain.push(serializer_class_name)

chain
end
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@bf4 So if you were referring to this part of code saying it was not easily understandable, then I agree. Suggestions? I could add comments, but I don't see how to make the code itself clearer.

@beauby beauby added this to the 0.10 milestone Oct 5, 2015
@beauby beauby self-assigned this Oct 5, 2015
@beauby
Copy link
Contributor Author

beauby commented Oct 7, 2015

Squashed.

ActiveModel::Serializer.serializer_for(resource)
end
serializer_context_class = options.fetch(:serializer_context_class, ActiveModel::Serializer)
serializer_class = options.fetch(:serializer) { serializer_context_class.serializer_for(resource) }
Copy link
Member

Choose a reason for hiding this comment

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

Potential 🐛 serializer_context_class is a required option. Would you mind adding a comment to the initializer to that effect? and if it's absent, it'll throw a KeyError. How do we want to handle that?

Maybe just say "don't use ArraySerializer directly, Just use SerializableResource" :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The previous line(serializer_context_class = options.fetch(:serializer_context_class, ActiveModel::Serializer)) ensures it is not required. Am I misunderstanding?

Copy link
Member

Choose a reason for hiding this comment

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

nope, I'm 👊 (facepalm?) oops never mind me

@beauby beauby changed the title Add support for nested and namespaced serializers Add support for nested serializers Oct 8, 2015
chain
end

# @api private
Copy link
Member

Choose a reason for hiding this comment

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

giving us the license to change it :) 👍

@beauby
Copy link
Contributor Author

beauby commented Oct 8, 2015

The build failed on appveyor, not sure why as I can't consult the logs.

@beauby
Copy link
Contributor Author

beauby commented Oct 8, 2015

Actually, I have the answer:

Build execution time has reached the maximum allowed time for your plan (40 minutes).

@bf4
Copy link
Member

bf4 commented Oct 9, 2015

Yikes. I'll write a timeout max for ci

B mobile phone

On Oct 8, 2015, at 5:54 PM, Lucas Hosseini notifications@github.com wrote:

Actually, I have the answer:

Build execution time has reached the maximum allowed time for your plan (40 minutes).


Reply to this email directly or view it on GitHub.

@bf4
Copy link
Member

bf4 commented Oct 9, 2015

Yikes. I'll write a timeout max for ci

hmm, I don't really know how to do around hooks Minitest without hacking it

@bf4
Copy link
Member

bf4 commented Oct 9, 2015

oh weird, it succeeded build success, just never exited, it appears

@bf4
Copy link
Member

bf4 commented Oct 9, 2015

try git commit -m 'rebuild appveyour' --allow-empty; git push -f to force it to rebuild?

@beauby beauby force-pushed the nested-serializer-lookup branch 2 times, most recently from 67c72e7 to 9147469 Compare October 9, 2015 13:57
@NullVoxPopuli
Copy link
Contributor

👍 LGTM

NullVoxPopuli added a commit that referenced this pull request Oct 9, 2015
@NullVoxPopuli NullVoxPopuli merged commit 6018ef1 into rails-api:master Oct 9, 2015
@bf4 bf4 deleted the nested-serializer-lookup branch October 12, 2015 00:57
bdmac added a commit to TYMessaging/active_model_serializers that referenced this pull request Nov 20, 2015
Adds support for finding serializers based on the "current" serializers
namespace to support things like serializer versioning. Without this you
have to be explicit in naming which serializer to use in all of your
serializer associations. That's OK usually (albeit annoying) but it
breaks polymorphism since you can't really specify the right serializer
ahead of time.

I came across a bunch of PRs such as rails-api#1225 that talk about different
versions of namespacing based on modules or controllers or whatever and
some of them even talk about supporting serializer namespaces but I have
been unable to find one that actually does this part of it. If there is
already work being done for this, feel free to ignore this PR but we
needed this for our current work.

This PR builds on top of the work done by @beauby in rails-api#1225 to add
support for namespaced serializer lookups. @beauby's work only allowed
for actual nesting of serializers withing a namespaced serializer (e.g.
for overrides) but did not actually walk up the tree to siblings or
serializers farther up the inheritance/namespace tree.

It simply modifies `Serializer#serializer_lookup_chain_for` to add all
of the possible levels of namespaces based on the current serializer.
With this patch for example if we have:
```ruby
class Public::V1::PostSerializer
  belongs_to :author
end

class Public::V1::AuthorSerializer
end
```
we will wind up with the following items in the lookup chain for an
author when serializing a Post with Public::V1::PostSerializer:
```ruby
['Public::V1::PostSerializer::AuthorSerializer',
'Public::V1::AuthorSerializer', 'Public::AuthorSerializer',
'::AuthorSerializer']
```
@bdmac bdmac mentioned this pull request Nov 20, 2015
bdmac added a commit to TYMessaging/active_model_serializers that referenced this pull request Nov 20, 2015
Adds support for finding serializers based on the "current" serializers
namespace to support things like serializer versioning. Without this you
have to be explicit in naming which serializer to use in all of your
serializer associations. That's OK usually (albeit annoying) but it
breaks polymorphism since you can't really specify the right serializer
ahead of time.

I came across a bunch of PRs such as rails-api#1225 that talk about different
versions of namespacing based on modules or controllers or whatever and
some of them even talk about supporting serializer namespaces but I have
been unable to find one that actually does this part of it. If there is
already work being done for this, feel free to ignore this PR but we
needed this for our current work.

This PR builds on top of the work done by @beauby in rails-api#1225 to add
support for namespaced serializer lookups. @beauby's work only allowed
for actual nesting of serializers withing a namespaced serializer (e.g.
for overrides) but did not actually walk up the tree to siblings or
serializers farther up the inheritance/namespace tree.

It simply modifies `Serializer#serializer_lookup_chain_for` to add all
of the possible levels of namespaces based on the current serializer.
With this patch for example if we have:
```ruby
class Public::V1::PostSerializer
  belongs_to :author
end

class Public::V1::AuthorSerializer
end
```
we will wind up with the following items in the lookup chain for an
author when serializing a Post with Public::V1::PostSerializer:
```ruby
['Public::V1::PostSerializer::AuthorSerializer',
'Public::V1::AuthorSerializer', 'Public::AuthorSerializer',
'::AuthorSerializer']
```
bdmac added a commit to TYMessaging/active_model_serializers that referenced this pull request Jan 22, 2016
Adds support for finding serializers based on the "current" serializers
namespace to support things like serializer versioning. Without this you
have to be explicit in naming which serializer to use in all of your
serializer associations. That's OK usually (albeit annoying) but it
breaks polymorphism since you can't really specify the right serializer
ahead of time.

I came across a bunch of PRs such as rails-api#1225 that talk about different
versions of namespacing based on modules or controllers or whatever and
some of them even talk about supporting serializer namespaces but I have
been unable to find one that actually does this part of it. If there is
already work being done for this, feel free to ignore this PR but we
needed this for our current work.

This PR builds on top of the work done by @beauby in rails-api#1225 to add
support for namespaced serializer lookups. @beauby's work only allowed
for actual nesting of serializers withing a namespaced serializer (e.g.
for overrides) but did not actually walk up the tree to siblings or
serializers farther up the inheritance/namespace tree.

It simply modifies `Serializer#serializer_lookup_chain_for` to add all
of the possible levels of namespaces based on the current serializer.
With this patch for example if we have:
```ruby
class Public::V1::PostSerializer
  belongs_to :author
end

class Public::V1::AuthorSerializer
end
```
we will wind up with the following items in the lookup chain for an
author when serializing a Post with Public::V1::PostSerializer:
```ruby
['Public::V1::PostSerializer::AuthorSerializer',
'Public::V1::AuthorSerializer', 'Public::AuthorSerializer',
'::AuthorSerializer']
```
atomaka added a commit to atomaka/dokkan-data-rails that referenced this pull request Jul 20, 2016
Match current API endpoints (/links, /characters)

There is a pull request that is currently active (within the last day) for Active Model Serializers that will allow for nested and inline Serializers.  This will allow `CardSerializer` to go from the complicated monstrosity that it is to a much simpler representation. For example

```
has_one :character
```

instead of:

```
def character
  Api::V1::CharacterSerializer.new(object.character)
end
```

follow this pull request at rails-api/active_model_serializers#1225

See merge request !1
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.

None yet

3 participants