diff --git a/docs/general/serializers.md b/docs/general/serializers.md index 67a14c2a6..250c477eb 100644 --- a/docs/general/serializers.md +++ b/docs/general/serializers.md @@ -111,6 +111,10 @@ e.g. class UserProfileSerializer < ActiveModel::Serializer type 'profile' end + +class UserSerializer < ActiveModel::Serializer + type { object.type } +end ``` #### ::link diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index 48f57edce..f7358cbe3 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -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) diff --git a/lib/active_model/serializer/adapter/json_api.rb b/lib/active_model/serializer/adapter/json_api.rb index 1c7f7226b..e7afb90cb 100644 --- a/lib/active_model/serializer/adapter/json_api.rb +++ b/lib/active_model/serializer/adapter/json_api.rb @@ -113,12 +113,13 @@ 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 - else - serializer.object.class.model_name.plural + value_or_block = serializer._type + if value_or_block + return serializer.instance_eval(&value_or_block) if value_or_block.respond_to?(:call) + return value_or_block end + inflection = ActiveModelSerializers.config.jsonapi_resource_type + serializer.object.class.model_name.public_send(inflection) end def resource_identifier_id_for(serializer) diff --git a/test/adapter/json_api/resource_type_config_test.rb b/test/adapter/json_api/resource_type_config_test.rb index f67ecca73..7deb70713 100644 --- a/test/adapter/json_api/resource_type_config_test.rb +++ b/test/adapter/json_api/resource_type_config_test.rb @@ -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] @@ -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