Skip to content

ActiveModel::Serializer::type now accepts a block #1399

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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/general/serializers.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ e.g.
class UserProfileSerializer < ActiveModel::Serializer
type 'profile'
end

class UserSerializer < ActiveModel::Serializer
type { object.type }
end
```

#### ::link
Expand Down
5 changes: 3 additions & 2 deletions lib/active_model/serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,9 @@ def self.inherited(base)
# @example
# class AdminAuthorSerializer < ActiveModel::Serializer
# type 'authors'
def self.type(type)
self._type = type
# type { object.type }
def self.type(type = nil, &block)
self._type = block || type
end

def self.link(name, value = nil, &block)
Expand Down
16 changes: 12 additions & 4 deletions lib/active_model/serializer/adapter/json_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,19 @@ def serializable_hash_for_single_resource
end

def resource_identifier_type_for(serializer)
return serializer._type if serializer._type
if ActiveModelSerializers.config.jsonapi_resource_type == :singular
serializer.object.class.model_name.singular
value_or_block = serializer._type
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 I'd rather see in implementation more like in #1370 and #1383 and note https://github.com/rails-api/active_model_serializers/pull/1370/files#r48116422 hasn't yet be resolved.

cc @beauby

Does that make sense? There's a lot going on in this method because there's uncertainty about how to handle the value being passed way down.

if value_or_block
if value_or_block.respond_to?(:call)
serializer.instance_eval(&value_or_block)
else
value_or_block
end
else
serializer.object.class.model_name.plural
if ActiveModelSerializers.config.jsonapi_resource_type == :singular
serializer.object.class.model_name.singular
else
serializer.object.class.model_name.plural
end
end
end

Expand Down
57 changes: 42 additions & 15 deletions test/adapter/json_api/resource_type_config_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,24 @@ class ProfileTypeSerializer < ActiveModel::Serializer
type 'profile'
end

class SpecialProfileTypeSerializer < ProfileTypeSerializer
type 'special_profile'
end

class PostTypeSerializer < ActiveModel::Serializer
type { object.type }
end

class SpecialPostTypeSerializer < PostTypeSerializer
type { 'special_post' }
end

def setup
@author = Author.new(id: 1, name: 'Steve K.')
@author.bio = nil
@author.roles = []
@blog = Blog.new(id: 23, name: 'AMS Blog')
@post = Post.new(id: 42, title: 'New Post', body: 'Body')
@post = Post.new(id: 42, title: 'New Post', body: 'Body', type: 'block_post')
@anonymous_post = Post.new(id: 43, title: 'Hello!!', body: 'Hello, world!!')
@comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
@post.comments = [@comment]
Expand All @@ -32,35 +44,50 @@ def setup
@author.posts = []
end

def with_jsonapi_resource_type type
old_type = ActiveModelSerializers.config.jsonapi_resource_type
ActiveModelSerializers.config.jsonapi_resource_type = type
yield
ensure
ActiveModelSerializers.config.jsonapi_resource_type = old_type
end

def test_config_plural
with_jsonapi_resource_type :plural do
hash = serializable(@comment, adapter: :json_api).serializable_hash
assert_equal('comments', hash[:data][:type])
assert_type('comments', @comment)
end
end

def test_config_singular
with_jsonapi_resource_type :singular do
hash = serializable(@comment, adapter: :json_api).serializable_hash
assert_equal('comment', hash[:data][:type])
assert_type('comment', @comment)
end
end

def test_explicit_type_value
hash = serializable(@author, serializer: ProfileTypeSerializer, adapter: :json_api).serializable_hash
assert_equal('profile', hash.fetch(:data).fetch(:type))
assert_type('profile', @author, serializer: ProfileTypeSerializer)
end

def test_explicit_type_value_for_subclass
Copy link
Member Author

Choose a reason for hiding this comment

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

Regression spec to make sure inheritance doesn't break anything.

assert_type('special_profile', @author, serializer: SpecialProfileTypeSerializer)
end

def test_explicit_type_block
assert_type('block_post', @post, serializer: PostTypeSerializer)
end

def test_explicit_type_block_for_subclass
assert_type('special_post', @post, serializer: SpecialPostTypeSerializer)
end

private

def with_jsonapi_resource_type type
Copy link
Member Author

Choose a reason for hiding this comment

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

Simply moved this method to be private.

old_type = ActiveModelSerializers.config.jsonapi_resource_type
ActiveModelSerializers.config.jsonapi_resource_type = type
yield
ensure
ActiveModelSerializers.config.jsonapi_resource_type = old_type
end

def assert_type(type, object, options = {})
Copy link
Member Author

Choose a reason for hiding this comment

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

The same code was used within every test so I packed it up into this method.

options.merge!(adapter: :json_api)
hash = serializable(object, options).serializable_hash
assert_equal(type, hash.fetch(:data).fetch(:type))
end

def serializable(resource, options = {})
ActiveModel::SerializableResource.new(resource, options)
end
Expand Down