mirror of
https://github.com/ditkrg/active_model_serializers.git
synced 2026-01-23 06:16:50 +00:00
Follow up to #1454
PR #1454 was merged with some missing fixes. All these fixes are addressed by this commit: - Rename ActiveModel::Serializer::Adapter::JsonApi::Association to ActiveModel::Serializer::Adapter::JsonApi::Relationship - Move ActiveModel::Serializer::Adapter:: JsonApi::Relationship and ActiveModel::Serializer::Adapter::JsonApi::ResourceIdentifier to ActiveModel::Serializer::Adapter::JsonApi::ApiObjects module - Add unit test for ActiveModel::Serializer::Adapter::JsonApi::Relationship - Add unit test for ActiveModel::Serializer::Adapter::JsonApi::ResourceIdentifier
This commit is contained in:
parent
fe6d2da46f
commit
2c4193851b
@ -1,14 +1,19 @@
|
|||||||
## 0.10.x
|
## 0.10.x
|
||||||
|
|
||||||
Breaking changes:
|
Breaking changes:
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
- [#1504](https://github.com/rails-api/active_model_serializers/pull/1504) Adds the changes missing from #1454
|
||||||
|
and add more tests for resource identifier and relationship objects. (@groyoh)
|
||||||
- [#1018](https://github.com/rails-api/active_model_serializers/pull/1018) Add more tests and docs for top-level links. (@leandrocp)
|
- [#1018](https://github.com/rails-api/active_model_serializers/pull/1018) Add more tests and docs for top-level links. (@leandrocp)
|
||||||
- [#1454](https://github.com/rails-api/active_model_serializers/pull/1454) Add support for
|
- [#1454](https://github.com/rails-api/active_model_serializers/pull/1454) Add support for
|
||||||
relationship-level links and meta attributes. (@beauby)
|
relationship-level links and meta attributes. (@beauby)
|
||||||
- [#1340](https://github.com/rails-api/active_model_serializers/pull/1340) Add support for resource-level meta. (@beauby)
|
- [#1340](https://github.com/rails-api/active_model_serializers/pull/1340) Add support for resource-level meta. (@beauby)
|
||||||
|
|
||||||
Fixes:
|
Fixes:
|
||||||
- [#1501](https://github.com/rails-api/active_model_serializers/pull/1501) Adds tests for SerializableResource::use_adapter?,doc typos (@domitian)
|
- [#1501](https://github.com/rails-api/active_model_serializers/pull/1501) Adds tests for SerializableResource::use_adapter?,doc typos (@domitian)
|
||||||
- [#1488](https://github.com/rails-api/active_model_serializers/pull/1488) Require ActiveSupport's string inflections (@nate00)
|
- [#1488](https://github.com/rails-api/active_model_serializers/pull/1488) Require ActiveSupport's string inflections (@nate00)
|
||||||
|
|
||||||
Misc:
|
Misc:
|
||||||
|
|
||||||
### v0.10.0.rc4 (2016/01/27 11:00 +00:00)
|
### v0.10.0.rc4 (2016/01/27 11:00 +00:00)
|
||||||
|
|||||||
@ -6,10 +6,9 @@ module ActiveModel
|
|||||||
autoload :PaginationLinks
|
autoload :PaginationLinks
|
||||||
autoload :FragmentCache
|
autoload :FragmentCache
|
||||||
autoload :Link
|
autoload :Link
|
||||||
autoload :Association
|
|
||||||
autoload :ResourceIdentifier
|
|
||||||
autoload :Meta
|
autoload :Meta
|
||||||
autoload :Deserialization
|
autoload :Deserialization
|
||||||
|
require 'active_model/serializer/adapter/json_api/api_objects'
|
||||||
|
|
||||||
# TODO: if we like this abstraction and other API objects to it,
|
# TODO: if we like this abstraction and other API objects to it,
|
||||||
# then extract to its own file and require it.
|
# then extract to its own file and require it.
|
||||||
@ -100,7 +99,7 @@ module ActiveModel
|
|||||||
end
|
end
|
||||||
|
|
||||||
def process_resource(serializer, primary)
|
def process_resource(serializer, primary)
|
||||||
resource_identifier = JsonApi::ResourceIdentifier.new(serializer).as_json
|
resource_identifier = ApiObjects::ResourceIdentifier.new(serializer).as_json
|
||||||
return false unless @resource_identifiers.add?(resource_identifier)
|
return false unless @resource_identifiers.add?(resource_identifier)
|
||||||
|
|
||||||
resource_object = resource_object_for(serializer)
|
resource_object = resource_object_for(serializer)
|
||||||
@ -136,7 +135,7 @@ module ActiveModel
|
|||||||
|
|
||||||
def resource_object_for(serializer)
|
def resource_object_for(serializer)
|
||||||
resource_object = cache_check(serializer) do
|
resource_object = cache_check(serializer) do
|
||||||
resource_object = JsonApi::ResourceIdentifier.new(serializer).as_json
|
resource_object = ApiObjects::ResourceIdentifier.new(serializer).as_json
|
||||||
|
|
||||||
requested_fields = fieldset && fieldset.fields_for(resource_object[:type])
|
requested_fields = fieldset && fieldset.fields_for(resource_object[:type])
|
||||||
attributes = attributes_for(serializer, requested_fields)
|
attributes = attributes_for(serializer, requested_fields)
|
||||||
@ -160,12 +159,13 @@ module ActiveModel
|
|||||||
def relationships_for(serializer, requested_associations)
|
def relationships_for(serializer, requested_associations)
|
||||||
include_tree = IncludeTree.from_include_args(requested_associations)
|
include_tree = IncludeTree.from_include_args(requested_associations)
|
||||||
serializer.associations(include_tree).each_with_object({}) do |association, hash|
|
serializer.associations(include_tree).each_with_object({}) do |association, hash|
|
||||||
hash[association.key] = JsonApi::Association.new(serializer,
|
hash[association.key] = ApiObjects::Relationship.new(
|
||||||
|
serializer,
|
||||||
association.serializer,
|
association.serializer,
|
||||||
association.options,
|
association.options,
|
||||||
association.links,
|
association.links,
|
||||||
association.meta)
|
association.meta
|
||||||
.as_json
|
).as_json
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
13
lib/active_model/serializer/adapter/json_api/api_objects.rb
Normal file
13
lib/active_model/serializer/adapter/json_api/api_objects.rb
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
module Adapter
|
||||||
|
class JsonApi
|
||||||
|
module ApiObjects
|
||||||
|
extend ActiveSupport::Autoload
|
||||||
|
autoload :Relationship
|
||||||
|
autoload :ResourceIdentifier
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
module Adapter
|
||||||
|
class JsonApi
|
||||||
|
module ApiObjects
|
||||||
|
class Relationship
|
||||||
|
def initialize(parent_serializer, serializer, options = {}, links = {}, meta = nil)
|
||||||
|
@object = parent_serializer.object
|
||||||
|
@scope = parent_serializer.scope
|
||||||
|
|
||||||
|
@options = options
|
||||||
|
@data = data_for(serializer, options)
|
||||||
|
@links = links.each_with_object({}) do |(key, value), hash|
|
||||||
|
hash[key] = Link.new(parent_serializer, value).as_json
|
||||||
|
end
|
||||||
|
@meta = meta.respond_to?(:call) ? parent_serializer.instance_eval(&meta) : meta
|
||||||
|
end
|
||||||
|
|
||||||
|
def as_json
|
||||||
|
hash = {}
|
||||||
|
hash[:data] = data if options[:include_data]
|
||||||
|
links = self.links
|
||||||
|
hash[:links] = links if links.any?
|
||||||
|
meta = self.meta
|
||||||
|
hash[:meta] = meta if meta
|
||||||
|
|
||||||
|
hash
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
attr_reader :object, :scope, :data, :options, :links, :meta
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def data_for(serializer, options)
|
||||||
|
if serializer.respond_to?(:each)
|
||||||
|
serializer.map { |s| ResourceIdentifier.new(s).as_json }
|
||||||
|
else
|
||||||
|
if options[:virtual_value]
|
||||||
|
options[:virtual_value]
|
||||||
|
elsif serializer && serializer.object
|
||||||
|
ResourceIdentifier.new(serializer).as_json
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
module Adapter
|
||||||
|
class JsonApi
|
||||||
|
module ApiObjects
|
||||||
|
class ResourceIdentifier
|
||||||
|
def initialize(serializer)
|
||||||
|
@id = id_for(serializer)
|
||||||
|
@type = type_for(serializer)
|
||||||
|
end
|
||||||
|
|
||||||
|
def as_json
|
||||||
|
{ id: id, type: type }
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
attr_reader :id, :type
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def 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
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def id_for(serializer)
|
||||||
|
serializer.read_attribute_for_serialization(:id).to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -1,48 +0,0 @@
|
|||||||
module ActiveModel
|
|
||||||
class Serializer
|
|
||||||
module Adapter
|
|
||||||
class JsonApi
|
|
||||||
class Association
|
|
||||||
def initialize(parent_serializer, serializer, options, links, meta)
|
|
||||||
@object = parent_serializer.object
|
|
||||||
@scope = parent_serializer.scope
|
|
||||||
|
|
||||||
@options = options
|
|
||||||
@data = data_for(serializer, options)
|
|
||||||
@links = links
|
|
||||||
.map { |key, value| { key => Link.new(parent_serializer, value).as_json } }
|
|
||||||
.reduce({}, :merge)
|
|
||||||
@meta = meta.respond_to?(:call) ? parent_serializer.instance_eval(&meta) : meta
|
|
||||||
end
|
|
||||||
|
|
||||||
def as_json
|
|
||||||
hash = {}
|
|
||||||
hash[:data] = @data if @options[:include_data]
|
|
||||||
hash[:links] = @links if @links.any?
|
|
||||||
hash[:meta] = @meta if @meta
|
|
||||||
|
|
||||||
hash
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
attr_reader :object, :scope
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def data_for(serializer, options)
|
|
||||||
if serializer.respond_to?(:each)
|
|
||||||
serializer.map { |s| ResourceIdentifier.new(s).as_json }
|
|
||||||
else
|
|
||||||
if options[:virtual_value]
|
|
||||||
options[:virtual_value]
|
|
||||||
elsif serializer && serializer.object
|
|
||||||
ResourceIdentifier.new(serializer).as_json
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
module ActiveModel
|
|
||||||
class Serializer
|
|
||||||
module Adapter
|
|
||||||
class JsonApi
|
|
||||||
class ResourceIdentifier
|
|
||||||
def initialize(serializer)
|
|
||||||
@id = id_for(serializer)
|
|
||||||
@type = type_for(serializer)
|
|
||||||
end
|
|
||||||
|
|
||||||
def as_json
|
|
||||||
{ id: @id.to_s, type: @type }
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
attr_reader :object, :scope
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def 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
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def id_for(serializer)
|
|
||||||
if serializer.respond_to?(:id)
|
|
||||||
serializer.id
|
|
||||||
else
|
|
||||||
serializer.object.id
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
168
test/adapter/json_api/api_objects/relationship_test.rb
Normal file
168
test/adapter/json_api/api_objects/relationship_test.rb
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
module Adapter
|
||||||
|
class JsonApi
|
||||||
|
module ApiObjects
|
||||||
|
class RelationshipTest < ActiveSupport::TestCase
|
||||||
|
def setup
|
||||||
|
@blog = Blog.new(id: 1)
|
||||||
|
@author = Author.new(id: 1, name: 'Steve K.', blog: @blog)
|
||||||
|
@serializer = BlogSerializer.new(@blog)
|
||||||
|
ActionController::Base.cache_store.clear
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_with_data
|
||||||
|
expected = {
|
||||||
|
data: {
|
||||||
|
id: '1',
|
||||||
|
type: 'blogs'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test_relationship(expected, options: { include_data: true })
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_with_nil_model
|
||||||
|
@serializer = BlogSerializer.new(nil)
|
||||||
|
expected = { data: nil }
|
||||||
|
test_relationship(expected, options: { include_data: true })
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_with_nil_serializer
|
||||||
|
@serializer = nil
|
||||||
|
expected = { data: nil }
|
||||||
|
test_relationship(expected, options: { include_data: true })
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_with_data_array
|
||||||
|
posts = [Post.new(id: 1), Post.new(id: 2)]
|
||||||
|
@serializer = ActiveModel::Serializer::ArraySerializer.new(posts)
|
||||||
|
@author.posts = posts
|
||||||
|
@author.blog = nil
|
||||||
|
expected = {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
type: 'posts'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
type: 'posts'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
test_relationship(expected, options: { include_data: true })
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_data_not_included
|
||||||
|
test_relationship({}, options: { include_data: false })
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_simple_link
|
||||||
|
links = { self: 'a link' }
|
||||||
|
test_relationship({ links: { self: 'a link' } }, links: links)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_many_links
|
||||||
|
links = {
|
||||||
|
self: 'a link',
|
||||||
|
related: 'another link'
|
||||||
|
}
|
||||||
|
expected = {
|
||||||
|
links: {
|
||||||
|
self: 'a link',
|
||||||
|
related: 'another link'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test_relationship(expected, links: links)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_block_link
|
||||||
|
links = { self: proc { "#{object.id}" } }
|
||||||
|
expected = { links: { self: "#{@blog.id}" } }
|
||||||
|
test_relationship(expected, links: links)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_block_link_with_meta
|
||||||
|
links = {
|
||||||
|
self: proc do
|
||||||
|
href "#{object.id}"
|
||||||
|
meta(id: object.id)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
expected = {
|
||||||
|
links: {
|
||||||
|
self: {
|
||||||
|
href: "#{@blog.id}",
|
||||||
|
meta: { id: @blog.id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test_relationship(expected, links: links)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_simple_meta
|
||||||
|
meta = { id: '1' }
|
||||||
|
expected = { meta: meta }
|
||||||
|
test_relationship(expected, meta: meta)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_block_meta
|
||||||
|
meta = proc do
|
||||||
|
{ id: object.id }
|
||||||
|
end
|
||||||
|
expected = {
|
||||||
|
meta: {
|
||||||
|
id: @blog.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test_relationship(expected, meta: meta)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_relationship_with_everything
|
||||||
|
links = {
|
||||||
|
self: 'a link',
|
||||||
|
related: proc do
|
||||||
|
href "#{object.id}"
|
||||||
|
meta object.id
|
||||||
|
end
|
||||||
|
|
||||||
|
}
|
||||||
|
meta = proc do
|
||||||
|
{ id: object.id }
|
||||||
|
end
|
||||||
|
expected = {
|
||||||
|
data: {
|
||||||
|
id: '1',
|
||||||
|
type: 'blogs'
|
||||||
|
},
|
||||||
|
links: {
|
||||||
|
self: 'a link',
|
||||||
|
related: {
|
||||||
|
href: '1', meta: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
meta: {
|
||||||
|
id: @blog.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test_relationship(expected, meta: meta, options: { include_data: true }, links: links)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def test_relationship(expected, params = {})
|
||||||
|
options = params.fetch(:options, {})
|
||||||
|
links = params.fetch(:links, {})
|
||||||
|
meta = params[:meta]
|
||||||
|
parent_serializer = AuthorSerializer.new(@author)
|
||||||
|
relationship = Relationship.new(parent_serializer, @serializer, options, links, meta)
|
||||||
|
assert_equal(expected, relationship.as_json)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,88 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
module Adapter
|
||||||
|
class JsonApi
|
||||||
|
module ApiObjects
|
||||||
|
class ResourceIdentifierTest < ActiveSupport::TestCase
|
||||||
|
class WithDefinedTypeSerializer < Serializer
|
||||||
|
type 'with_defined_type'
|
||||||
|
end
|
||||||
|
|
||||||
|
class WithDefinedIdSerializer < Serializer
|
||||||
|
def id
|
||||||
|
'special_id'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class FragmentedSerializer < Serializer; end
|
||||||
|
|
||||||
|
def setup
|
||||||
|
@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_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
|
||||||
|
FragmentedSerializer.fragmented(WithDefinedIdSerializer.new(@author))
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
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
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Reference in New Issue
Block a user