Skip to content

Commit

Permalink
ActiveModel::Serializer::type accepts a block
Browse files Browse the repository at this point in the history
A block passed to the type method will be instance_eval'd to the serializer.
This allows us to avoid overriding the #_type method to have a dynamic type.
  • Loading branch information
Yohan Robert committed Dec 26, 2015
1 parent bb67735 commit 18a7315
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 21 deletions.
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
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
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
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 = {})
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

0 comments on commit 18a7315

Please sign in to comment.