From 87d587e1af0b4c8f12eeb9fb9e0e2a596bdece57 Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Wed, 16 Sep 2015 09:56:28 -0500 Subject: [PATCH] Move JsonApi object config to JsonApi adapter Finish #1147 --- docs/general/configuration_options.md | 8 ++- lib/active_model/serializable_resource.rb | 3 +- .../serializer/adapter/json_api.rb | 37 ++++++------ .../adapter/json_api/toplevel_jsonapi_test.rb | 60 +++++++++---------- test/support/serialization_testing.rb | 19 ++++++ 5 files changed, 73 insertions(+), 54 deletions(-) diff --git a/docs/general/configuration_options.md b/docs/general/configuration_options.md index 5981d5f00..df3f000c5 100644 --- a/docs/general/configuration_options.md +++ b/docs/general/configuration_options.md @@ -9,5 +9,9 @@ The following configuration options can be set on `ActiveModel::Serializer.confi ## JSON API - `jsonapi_resource_type`: Whether the `type` attributes of resources should be singular or plural. Possible values: `:singular, :plural`. Default: `:plural`. -- `jsonapi_toplevel_member`: Whether to include a [top level JSON API member](http://jsonapi.org/format/#document-jsonapi-object) in the response document. Default: `false`. -- `jsonapi_version`: The latest version of the spec the API conforms to. Used when `jsonapi_toplevel_member` is `true`. Default: `'1.0'`. +- `jsonapi_toplevel_member`: Whether to include a [top level JSON API member](http://jsonapi.org/format/#document-jsonapi-object) + in the response document. Default: `false`. +- `jsonapi_version`: The latest version of the spec the API conforms to. + Used when `jsonapi_toplevel_member` is `true`. Default: `'1.0'`. +- `jsonapi_toplevel_meta`: Optional metadata. Not included if empty. + Used when `jsonapi_toplevel_member` is `true`. Default: `{}`. diff --git a/lib/active_model/serializable_resource.rb b/lib/active_model/serializable_resource.rb index 99820664f..0791385bc 100644 --- a/lib/active_model/serializable_resource.rb +++ b/lib/active_model/serializable_resource.rb @@ -1,8 +1,7 @@ require 'set' module ActiveModel class SerializableResource - ADAPTER_OPTION_KEYS = Set.new([:include, :fields, :adapter, - :jsonapi_toplevel_meta]) + ADAPTER_OPTION_KEYS = Set.new([:include, :fields, :adapter]) # Primary interface to composing a resource with a serializer and adapter. # @return the serializable_resource, ready for #as_json/#to_json/#serializable_hash. diff --git a/lib/active_model/serializer/adapter/json_api.rb b/lib/active_model/serializer/adapter/json_api.rb index 2079dd74d..5e13a97a8 100644 --- a/lib/active_model/serializer/adapter/json_api.rb +++ b/lib/active_model/serializer/adapter/json_api.rb @@ -1,16 +1,24 @@ class ActiveModel::Serializer::Adapter::JsonApi < ActiveModel::Serializer::Adapter + # JsonApiObject: namespace for functions that build + # JSON API objects module JsonApiObject # Make JSON API top-level jsonapi member opt-in # ref: http://jsonapi.org/format/#document-top-level ActiveModel::Serializer.config.jsonapi_toplevel_member = false + ActiveModel::Serializer.config.jsonapi_version = '1.0' + ActiveModel::Serializer.config.jsonapi_toplevel_meta = {} module JsonApi - VERSION = "1.0" extend self def add!(document) return document unless ActiveModel::Serializer.config.jsonapi_toplevel_member - document.merge!( - jsonapi: { version: VERSION }, - ) + object = { + jsonapi: { + version: ActiveModel::Serializer.config.jsonapi_version, + meta: ActiveModel::Serializer.config.jsonapi_toplevel_meta + } + } + object[:jsonapi].reject! {|_,v| v.blank? } + document.merge!(object) end end end @@ -33,20 +41,11 @@ def initialize(serializer, options = {}) def serializable_hash(options = nil) options ||= {} - hash = - if serializer.respond_to?(:each) - serializable_hash_for_collection(serializer, options) - else - serializable_hash_for_single_resource(serializer, options) - end - - if ActiveModel::Serializer.config.jsonapi_toplevel_member - hash[:jsonapi] = {} - hash[:jsonapi][:version] = ActiveModel::Serializer.config.jsonapi_version - hash[:jsonapi][:meta] = @options[:jsonapi_toplevel_meta] if @options[:jsonapi_toplevel_meta] + if serializer.respond_to?(:each) + serializable_hash_for_collection(serializer, options) + else + serializable_hash_for_single_resource(serializer, options) end - - hash end def fragment_cache(cached_hash, non_cached_hash) @@ -141,8 +140,8 @@ def relationship_value_for(serializer, options = {}) end def relationships_for(serializer) - Hash[serializer.associations.map { |association| - [association.key, { data: relationship_value_for(association.serializer, association.options) }] + Hash[serializer.associations.map { |association| + [association.key, { data: relationship_value_for(association.serializer, association.options) }] }] end diff --git a/test/adapter/json_api/toplevel_jsonapi_test.rb b/test/adapter/json_api/toplevel_jsonapi_test.rb index a95da1aea..8758c65a5 100644 --- a/test/adapter/json_api/toplevel_jsonapi_test.rb +++ b/test/adapter/json_api/toplevel_jsonapi_test.rb @@ -27,58 +27,56 @@ def setup @author.posts = [] end - def with_config(option, value) - old_value = ActiveModel::Serializer.config[option] - ActiveModel::Serializer.config[option] = value - yield - ensure - ActiveModel::Serializer.config[option] = old_value + def test_toplevel_jsonapi_defaults_to_false + assert_equal config.fetch(:jsonapi_toplevel_member), false end def test_disable_toplevel_jsonapi - with_adapter :json_api do - with_config(:jsonapi_toplevel_member, false) do - hash = ActiveModel::SerializableResource.new(@post).serializable_hash - assert_nil(hash[:jsonapi]) - end + with_config(jsonapi_toplevel_member: false) do + hash = serialize(@post) + assert_nil(hash[:jsonapi]) end end def test_enable_toplevel_jsonapi - with_adapter :json_api do - with_config(:jsonapi_toplevel_member, true) do - hash = ActiveModel::SerializableResource.new(@post).serializable_hash - refute_nil(hash[:jsonapi]) - end + with_config(jsonapi_toplevel_member: true) do + hash = serialize(@post) + refute_nil(hash[:jsonapi]) end end def test_default_toplevel_jsonapi_version - with_adapter :json_api do - with_config(:jsonapi_toplevel_member, true) do - hash = ActiveModel::SerializableResource.new(@post).serializable_hash - assert_equal('1.0', hash[:jsonapi][:version]) - end + with_config(jsonapi_toplevel_member: true) do + hash = serialize(@post) + assert_equal('1.0', hash[:jsonapi][:version]) end end def test_toplevel_jsonapi_no_meta - with_adapter :json_api do - with_config(:jsonapi_toplevel_member, true) do - hash = ActiveModel::SerializableResource.new(@post).serializable_hash - assert_nil(hash[:jsonapi][:meta]) - end + with_config(jsonapi_toplevel_member: true) do + hash = serialize(@post) + assert_nil(hash[:jsonapi][:meta]) end end def test_toplevel_jsonapi_meta - with_adapter :json_api do - with_config(:jsonapi_toplevel_member, true) do - hash = ActiveModel::SerializableResource.new(@post, jsonapi_toplevel_meta: 'custom').serializable_hash - assert_equal('custom', hash[:jsonapi][:meta]) - end + new_config = { + jsonapi_toplevel_member: true, + jsonapi_toplevel_meta: { + 'copyright': 'Copyright 2015 Example Corp.' + } + } + with_config(new_config) do + hash = serialize(@post) + assert_equal(new_config[:jsonapi_toplevel_meta], hash.fetch(:jsonapi).fetch(:meta)) end end + + private + + def serialize(resource, options = {}) + serializable(resource, { adapter: :json_api}.merge!(options)).serializable_hash + end end end end diff --git a/test/support/serialization_testing.rb b/test/support/serialization_testing.rb index 38fcdf5ef..3114c1429 100644 --- a/test/support/serialization_testing.rb +++ b/test/support/serialization_testing.rb @@ -3,6 +3,8 @@ def before_setup ActionController::Base.cache_store.clear end + private + def with_adapter(adapter) old_adapter = ActiveModel::Serializer.config.adapter ActiveModel::Serializer.config.adapter = adapter @@ -10,4 +12,21 @@ def with_adapter(adapter) ensure ActiveModel::Serializer.config.adapter = old_adapter end + + def config + ActiveModel::Serializer.config + end + + def with_config(hash) + old_config = config.dup + ActiveModel::Serializer.config.update(hash) + yield + ensure + ActiveModel::Serializer.config.replace(old_config) + end + + def serializable(resource, options = {}) + ActiveModel::SerializableResource.new(resource, options) + end + end