diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bd18c868..3904151e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,8 @@ Fixes: - [#1488](https://github.com/rails-api/active_model_serializers/pull/1488) Require ActiveSupport's string inflections (@nate00) Misc: +- [#1529](https://github.com/rails-api/active_model_serializers/pull/1529) Move ApiObjects to the JsonApi namespace + as a follow up to #1504. (@groyoh) - [#1497](https://github.com/rails-api/active_model_serializers/pull/1497) Add JRuby-9000 to appveyor.yml(@corainchicago) ### v0.10.0.rc4 (2016/01/27 11:00 +00:00) diff --git a/lib/active_model/serializer/adapter/json_api/api_objects.rb b/lib/active_model/serializer/adapter/json_api/api_objects.rb deleted file mode 100644 index bad3173c3..000000000 --- a/lib/active_model/serializer/adapter/json_api/api_objects.rb +++ /dev/null @@ -1,13 +0,0 @@ -module ActiveModel - class Serializer - module Adapter - class JsonApi - module ApiObjects - extend ActiveSupport::Autoload - autoload :Relationship - autoload :ResourceIdentifier - end - end - end - end -end diff --git a/lib/active_model/serializer/adapter/json_api/api_objects/relationship.rb b/lib/active_model/serializer/adapter/json_api/api_objects/relationship.rb deleted file mode 100644 index dfaabc39b..000000000 --- a/lib/active_model/serializer/adapter/json_api/api_objects/relationship.rb +++ /dev/null @@ -1,52 +0,0 @@ -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] = ActiveModelSerializers::Adapter::JsonApi::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 diff --git a/lib/active_model/serializer/adapter/json_api/api_objects/resource_identifier.rb b/lib/active_model/serializer/adapter/json_api/api_objects/resource_identifier.rb deleted file mode 100644 index 058f06031..000000000 --- a/lib/active_model/serializer/adapter/json_api/api_objects/resource_identifier.rb +++ /dev/null @@ -1,39 +0,0 @@ -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 diff --git a/lib/active_model_serializers/adapter/json_api.rb b/lib/active_model_serializers/adapter/json_api.rb index 841185f00..8885c01c6 100644 --- a/lib/active_model_serializers/adapter/json_api.rb +++ b/lib/active_model_serializers/adapter/json_api.rb @@ -7,7 +7,8 @@ class JsonApi < Base autoload :Link require 'active_model/serializer/adapter/json_api/meta' autoload :Deserialization - require 'active_model/serializer/adapter/json_api/api_objects' + autoload :ResourceIdentifier + autoload :Relationship # TODO: if we like this abstraction and other API objects to it, # then extract to its own file and require it. @@ -98,7 +99,7 @@ def resource_objects_for(serializers) end def process_resource(serializer, primary) - resource_identifier = ActiveModel::Serializer::Adapter::JsonApi::ApiObjects::ResourceIdentifier.new(serializer).as_json + resource_identifier = ResourceIdentifier.new(serializer).as_json return false unless @resource_identifiers.add?(resource_identifier) resource_object = resource_object_for(serializer) @@ -134,7 +135,7 @@ def attributes_for(serializer, fields) def resource_object_for(serializer) resource_object = cache_check(serializer) do - resource_object = ActiveModel::Serializer::Adapter::JsonApi::ApiObjects::ResourceIdentifier.new(serializer).as_json + resource_object = ResourceIdentifier.new(serializer).as_json requested_fields = fieldset && fieldset.fields_for(resource_object[:type]) attributes = attributes_for(serializer, requested_fields) @@ -158,7 +159,7 @@ def resource_object_for(serializer) def relationships_for(serializer, requested_associations) include_tree = ActiveModel::Serializer::IncludeTree.from_include_args(requested_associations) serializer.associations(include_tree).each_with_object({}) do |association, hash| - hash[association.key] = ActiveModel::Serializer::Adapter::JsonApi::ApiObjects::Relationship.new( + hash[association.key] = Relationship.new( serializer, association.serializer, association.options, diff --git a/lib/active_model_serializers/adapter/json_api/relationship.rb b/lib/active_model_serializers/adapter/json_api/relationship.rb new file mode 100644 index 000000000..a5923d2bf --- /dev/null +++ b/lib/active_model_serializers/adapter/json_api/relationship.rb @@ -0,0 +1,51 @@ +module ActiveModelSerializers + module Adapter + class JsonApi + class Relationship + def initialize(parent_serializer, serializer, options = {}, links = {}, meta = nil) + @options = options + @data = data_for(serializer, options) + @links = links_for(parent_serializer, links) + @meta = meta_for(parent_serializer, 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 :data, :options, :links, :meta + + private + + def links_for(parent_serializer, links) + links.each_with_object({}) do |(key, value), hash| + hash[key] = Link.new(parent_serializer, value).as_json + end + end + + def meta_for(parent_serializer, meta) + meta.respond_to?(:call) ? parent_serializer.instance_eval(&meta) : meta + end + + def data_for(serializer, options) + if serializer.respond_to?(:each) + serializer.map { |s| ResourceIdentifier.new(s).as_json } + elsif options[:virtual_value] + options[:virtual_value] + elsif serializer && serializer.object + ResourceIdentifier.new(serializer).as_json + end + end + end + end + end +end diff --git a/lib/active_model_serializers/adapter/json_api/resource_identifier.rb b/lib/active_model_serializers/adapter/json_api/resource_identifier.rb new file mode 100644 index 000000000..9a42fa63d --- /dev/null +++ b/lib/active_model_serializers/adapter/json_api/resource_identifier.rb @@ -0,0 +1,35 @@ +module ActiveModelSerializers + module Adapter + class JsonApi + 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 diff --git a/test/adapter/json_api/api_objects/relationship_test.rb b/test/adapter/json_api/api_objects/relationship_test.rb index 26577bc96..64d8c5494 100644 --- a/test/adapter/json_api/api_objects/relationship_test.rb +++ b/test/adapter/json_api/api_objects/relationship_test.rb @@ -1,166 +1,162 @@ 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 +module ActiveModelSerializers + module Adapter + class JsonApi + class RelationshipTest < ActiveSupport::TestCase + setup do + @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_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_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_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::CollectionSerializer.new(posts) - @author.posts = posts - @author.blog = nil - expected = { - data: [ - { - id: '1', - type: 'posts' - }, - { - id: '2', - type: 'posts' - } - ] + def test_relationship_with_data_array + posts = [Post.new(id: 1), Post.new(id: 2)] + @serializer = ActiveModel::Serializer::CollectionSerializer.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 + ] + } + test_relationship(expected, options: { include_data: true }) + end - def test_relationship_data_not_included - test_relationship({}, options: { include_data: false }) - 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_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_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 + 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) + 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_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_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 + 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 = 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 + }, + meta: { + id: @blog.id + } + } + test_relationship(expected, meta: meta, options: { include_data: true }, links: links) + end - private + 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 + 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 diff --git a/test/adapter/json_api/api_objects/resource_identifier_test.rb b/test/adapter/json_api/api_objects/resource_identifier_test.rb index a40f07071..0fc6d33ba 100644 --- a/test/adapter/json_api/api_objects/resource_identifier_test.rb +++ b/test/adapter/json_api/api_objects/resource_identifier_test.rb @@ -1,87 +1,84 @@ 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 +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; 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_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) + 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) + 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