mirror of
https://github.com/ditkrg/active_model_serializers.git
synced 2026-01-22 22:06:50 +00:00
Merge pull request #2216 from rails-api/serialize_resource_with_nil_id
Fix: Serialize resource type for unpersisted records (blank id)
This commit is contained in:
commit
3c5e11bb0f
@ -8,12 +8,13 @@ module ActiveModelSerializers
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.for_type_with_id(type, id, options)
|
def self.for_type_with_id(type, id, options)
|
||||||
return nil if id.blank?
|
|
||||||
type = inflect_type(type)
|
type = inflect_type(type)
|
||||||
{
|
type = type_for(:no_class_needed, type, options)
|
||||||
id: id.to_s,
|
if id.blank?
|
||||||
type: type_for(:no_class_needed, type, options)
|
{ type: type }
|
||||||
}
|
else
|
||||||
|
{ id: id.to_s, type: type }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.raw_type_from_serializer_object(object)
|
def self.raw_type_from_serializer_object(object)
|
||||||
@ -38,8 +39,11 @@ module ActiveModelSerializers
|
|||||||
end
|
end
|
||||||
|
|
||||||
def as_json
|
def as_json
|
||||||
return nil if id.blank?
|
if id.blank?
|
||||||
{ id: id, type: type }
|
{ type: type }
|
||||||
|
else
|
||||||
|
{ id: id.to_s, type: type }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|||||||
@ -1,110 +0,0 @@
|
|||||||
require 'test_helper'
|
|
||||||
|
|
||||||
module ActiveModelSerializers
|
|
||||||
module Adapter
|
|
||||||
class JsonApi
|
|
||||||
class ResourceIdentifierTest < ActiveSupport::TestCase
|
|
||||||
class WithDefinedTypeSerializer < ActiveModel::Serializer
|
|
||||||
type 'with_defined_type'
|
|
||||||
end
|
|
||||||
|
|
||||||
class WithDefinedIdSerializer < ActiveModel::Serializer
|
|
||||||
def id
|
|
||||||
'special_id'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class FragmentedSerializer < ActiveModel::Serializer
|
|
||||||
cache only: :id
|
|
||||||
|
|
||||||
def id
|
|
||||||
'special_id'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
setup do
|
|
||||||
@model = Author.new(id: 1, name: 'Steve K.')
|
|
||||||
ActionController::Base.cache_store.clear
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_defined_type
|
|
||||||
test_type(WithDefinedTypeSerializer, 'with-defined-type')
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_singular_type
|
|
||||||
test_type_inflection(AuthorSerializer, 'author', :singular)
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_plural_type
|
|
||||||
test_type_inflection(AuthorSerializer, 'authors', :plural)
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_type_with_namespace
|
|
||||||
Object.const_set(:Admin, Module.new)
|
|
||||||
model = Class.new(::Model)
|
|
||||||
Admin.const_set(:PowerUser, model)
|
|
||||||
serializer = Class.new(ActiveModel::Serializer)
|
|
||||||
Admin.const_set(:PowerUserSerializer, serializer)
|
|
||||||
with_namespace_separator '--' do
|
|
||||||
admin_user = Admin::PowerUser.new
|
|
||||||
serializer = Admin::PowerUserSerializer.new(admin_user)
|
|
||||||
expected = {
|
|
||||||
id: admin_user.id,
|
|
||||||
type: 'admin--power-users'
|
|
||||||
}
|
|
||||||
|
|
||||||
identifier = ResourceIdentifier.new(serializer, {})
|
|
||||||
actual = identifier.as_json
|
|
||||||
assert_equal(expected, actual)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_id_defined_on_object
|
|
||||||
test_id(AuthorSerializer, @model.id.to_s)
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_id_defined_on_serializer
|
|
||||||
test_id(WithDefinedIdSerializer, 'special_id')
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_id_defined_on_fragmented
|
|
||||||
test_id(FragmentedSerializer, 'special_id')
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def test_type_inflection(serializer_class, expected_type, inflection)
|
|
||||||
original_inflection = ActiveModelSerializers.config.jsonapi_resource_type
|
|
||||||
ActiveModelSerializers.config.jsonapi_resource_type = inflection
|
|
||||||
test_type(serializer_class, expected_type)
|
|
||||||
ensure
|
|
||||||
ActiveModelSerializers.config.jsonapi_resource_type = original_inflection
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_type(serializer_class, expected_type)
|
|
||||||
serializer = serializer_class.new(@model)
|
|
||||||
resource_identifier = ResourceIdentifier.new(serializer, nil)
|
|
||||||
expected = {
|
|
||||||
id: @model.id.to_s,
|
|
||||||
type: expected_type
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_equal(expected, resource_identifier.as_json)
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_id(serializer_class, id)
|
|
||||||
serializer = serializer_class.new(@model)
|
|
||||||
resource_identifier = ResourceIdentifier.new(serializer, nil)
|
|
||||||
inflection = ActiveModelSerializers.config.jsonapi_resource_type
|
|
||||||
type = @model.class.model_name.send(inflection)
|
|
||||||
expected = {
|
|
||||||
id: id,
|
|
||||||
type: type
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_equal(expected, resource_identifier.as_json)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@ -1,59 +1,191 @@
|
|||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
module ActiveModel
|
module ActiveModelSerializers
|
||||||
class Serializer
|
module Adapter
|
||||||
module Adapter
|
class JsonApi
|
||||||
class JsonApi
|
class TypeTest < ActiveSupport::TestCase
|
||||||
class TypeTest < ActiveSupport::TestCase
|
class StringTypeSerializer < ActiveModel::Serializer
|
||||||
class StringTypeSerializer < ActiveModel::Serializer
|
attribute :name
|
||||||
attribute :name
|
type 'profile'
|
||||||
type 'profile'
|
end
|
||||||
end
|
|
||||||
|
|
||||||
class SymbolTypeSerializer < ActiveModel::Serializer
|
class SymbolTypeSerializer < ActiveModel::Serializer
|
||||||
attribute :name
|
attribute :name
|
||||||
type :profile
|
type :profile
|
||||||
end
|
end
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
@author = Author.new(id: 1, name: 'Steve K.')
|
@author = Author.new(id: 1, name: 'Steve K.')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_config_plural
|
def test_config_plural
|
||||||
with_jsonapi_resource_type :plural do
|
with_jsonapi_inflection :plural do
|
||||||
assert_type(@author, 'authors')
|
assert_type(@author, 'authors')
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_config_singular
|
def test_config_singular
|
||||||
with_jsonapi_resource_type :singular do
|
with_jsonapi_inflection :singular do
|
||||||
assert_type(@author, 'author')
|
assert_type(@author, 'author')
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_explicit_string_type_value
|
def test_explicit_string_type_value
|
||||||
assert_type(@author, 'profile', serializer: StringTypeSerializer)
|
assert_type(@author, 'profile', serializer: StringTypeSerializer)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_explicit_symbol_type_value
|
||||||
|
assert_type(@author, 'profile', serializer: SymbolTypeSerializer)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def assert_type(resource, expected_type, opts = {})
|
||||||
|
opts = opts.reverse_merge(adapter: :json_api)
|
||||||
|
hash = serializable(resource, opts).serializable_hash
|
||||||
|
assert_equal(expected_type, hash.fetch(:data).fetch(:type))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
class ResourceIdentifierTest < ActiveSupport::TestCase
|
||||||
|
class WithDefinedTypeSerializer < ActiveModel::Serializer
|
||||||
|
type 'with_defined_types'
|
||||||
|
end
|
||||||
|
|
||||||
|
class WithDefinedIdSerializer < ActiveModel::Serializer
|
||||||
|
def id
|
||||||
|
'special_id'
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_explicit_symbol_type_value
|
class FragmentedSerializer < ActiveModel::Serializer
|
||||||
assert_type(@author, 'profile', serializer: SymbolTypeSerializer)
|
cache only: :id
|
||||||
|
|
||||||
|
def id
|
||||||
|
'special_id'
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
setup do
|
||||||
|
@model = Author.new(id: 1, name: 'Steve K.')
|
||||||
|
ActionController::Base.cache_store.clear
|
||||||
|
end
|
||||||
|
|
||||||
def assert_type(resource, expected_type, opts = {})
|
def test_defined_type
|
||||||
opts = opts.reverse_merge(adapter: :json_api)
|
actual = with_jsonapi_inflection :plural do
|
||||||
hash = serializable(resource, opts).serializable_hash
|
actual_resource_identifier_object(WithDefinedTypeSerializer, @model)
|
||||||
assert_equal(expected_type, hash.fetch(:data).fetch(:type))
|
|
||||||
end
|
end
|
||||||
|
expected = { id: expected_model_id(@model), type: 'with-defined-types' }
|
||||||
|
assert_equal actual, expected
|
||||||
|
end
|
||||||
|
|
||||||
def with_jsonapi_resource_type(inflection)
|
def test_defined_type_not_inflected
|
||||||
old_inflection = ActiveModelSerializers.config.jsonapi_resource_type
|
actual = with_jsonapi_inflection :singular do
|
||||||
ActiveModelSerializers.config.jsonapi_resource_type = inflection
|
actual_resource_identifier_object(WithDefinedTypeSerializer, @model)
|
||||||
yield
|
|
||||||
ensure
|
|
||||||
ActiveModelSerializers.config.jsonapi_resource_type = old_inflection
|
|
||||||
end
|
end
|
||||||
|
expected = { id: expected_model_id(@model), type: 'with-defined-types' }
|
||||||
|
assert_equal actual, expected
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_singular_type
|
||||||
|
actual = with_jsonapi_inflection :singular do
|
||||||
|
actual_resource_identifier_object(AuthorSerializer, @model)
|
||||||
|
end
|
||||||
|
expected = { id: expected_model_id(@model), type: 'author' }
|
||||||
|
assert_equal actual, expected
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_plural_type
|
||||||
|
actual = with_jsonapi_inflection :plural do
|
||||||
|
actual_resource_identifier_object(AuthorSerializer, @model)
|
||||||
|
end
|
||||||
|
expected = { id: expected_model_id(@model), type: 'authors' }
|
||||||
|
assert_equal actual, expected
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_type_with_namespace
|
||||||
|
Object.const_set(:Admin, Module.new)
|
||||||
|
model = Class.new(::Model)
|
||||||
|
Admin.const_set(:PowerUser, model)
|
||||||
|
serializer = Class.new(ActiveModel::Serializer)
|
||||||
|
Admin.const_set(:PowerUserSerializer, serializer)
|
||||||
|
with_namespace_separator '--' do
|
||||||
|
admin_user = Admin::PowerUser.new
|
||||||
|
serializer = Admin::PowerUserSerializer.new(admin_user)
|
||||||
|
expected = {
|
||||||
|
id: admin_user.id,
|
||||||
|
type: 'admin--power-users'
|
||||||
|
}
|
||||||
|
|
||||||
|
identifier = ResourceIdentifier.new(serializer, {})
|
||||||
|
actual = identifier.as_json
|
||||||
|
assert_equal(expected, actual)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_id_defined_on_object
|
||||||
|
actual = actual_resource_identifier_object(AuthorSerializer, @model)
|
||||||
|
expected = { id: @model.id.to_s, type: expected_model_type(@model) }
|
||||||
|
assert_equal actual, expected
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_blank_id
|
||||||
|
model = Author.new(id: nil, name: 'Steve K.')
|
||||||
|
actual = actual_resource_identifier_object(AuthorSerializer, model)
|
||||||
|
expected = { type: expected_model_type(model) }
|
||||||
|
assert_equal actual, expected
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_for_type_with_id
|
||||||
|
id = 1
|
||||||
|
actual = ResourceIdentifier.for_type_with_id('admin_user', id, {})
|
||||||
|
expected = { id: '1', type: 'admin-users' }
|
||||||
|
assert_equal actual, expected
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_for_type_with_id_given_blank_id
|
||||||
|
id = ''
|
||||||
|
actual = ResourceIdentifier.for_type_with_id('admin_user', id, {})
|
||||||
|
expected = { type: 'admin-users' }
|
||||||
|
assert_equal actual, expected
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_for_type_with_id_inflected
|
||||||
|
id = 2
|
||||||
|
actual = with_jsonapi_inflection :singular do
|
||||||
|
ResourceIdentifier.for_type_with_id('admin_users', id, {})
|
||||||
|
end
|
||||||
|
expected = { id: '2', type: 'admin-user' }
|
||||||
|
assert_equal actual, expected
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_id_defined_on_serializer
|
||||||
|
actual = actual_resource_identifier_object(WithDefinedIdSerializer, @model)
|
||||||
|
expected = { id: 'special_id', type: expected_model_type(@model) }
|
||||||
|
assert_equal actual, expected
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_id_defined_on_fragmented
|
||||||
|
actual = actual_resource_identifier_object(FragmentedSerializer, @model)
|
||||||
|
expected = { id: 'special_id', type: expected_model_type(@model) }
|
||||||
|
assert_equal actual, expected
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def actual_resource_identifier_object(serializer_class, model)
|
||||||
|
serializer = serializer_class.new(model)
|
||||||
|
resource_identifier = ResourceIdentifier.new(serializer, nil)
|
||||||
|
resource_identifier.as_json
|
||||||
|
end
|
||||||
|
|
||||||
|
def expected_model_type(model, inflection = ActiveModelSerializers.config.jsonapi_resource_type)
|
||||||
|
with_jsonapi_inflection inflection do
|
||||||
|
model.class.model_name.send(inflection)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def expected_model_id(model)
|
||||||
|
model.id.to_s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -47,6 +47,14 @@ module SerializationTesting
|
|||||||
ActiveModelSerializers.config.replace(old_config)
|
ActiveModelSerializers.config.replace(old_config)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def with_jsonapi_inflection(inflection)
|
||||||
|
original_inflection = ActiveModelSerializers.config.jsonapi_resource_type
|
||||||
|
ActiveModelSerializers.config.jsonapi_resource_type = inflection
|
||||||
|
yield
|
||||||
|
ensure
|
||||||
|
ActiveModelSerializers.config.jsonapi_resource_type = original_inflection
|
||||||
|
end
|
||||||
|
|
||||||
def with_serializer_lookup_disabled
|
def with_serializer_lookup_disabled
|
||||||
original_serializer_lookup = ActiveModelSerializers.config.serializer_lookup_enabled
|
original_serializer_lookup = ActiveModelSerializers.config.serializer_lookup_enabled
|
||||||
ActiveModelSerializers.config.serializer_lookup_enabled = false
|
ActiveModelSerializers.config.serializer_lookup_enabled = false
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user