From 8ab4c4a8b495922f45f3b0e013aea892c8eec25a Mon Sep 17 00:00:00 2001 From: Lucas Hosseini Date: Mon, 14 Sep 2015 06:12:21 +0200 Subject: [PATCH] Add support for top level jsonapi member. --- CHANGELOG.md | 3 +- docs/general/configuration_options.md | 2 + lib/active_model/serializable_resource.rb | 3 +- .../serializer/adapter/json_api.rb | 17 +++- lib/active_model/serializer/configuration.rb | 2 + .../adapter/json_api/toplevel_jsonapi_test.rb | 86 +++++++++++++++++++ 6 files changed, 107 insertions(+), 6 deletions(-) create mode 100644 test/adapter/json_api/toplevel_jsonapi_test.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index a5a8a744f..7b44127ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,4 +11,5 @@ * remove root key option and split JSON adapter [@joaomdmoura] * adds FlattenJSON as default adapter [@joaomdmoura] * adds support for `pagination links` at top level of JsonApi adapter [@bacarini] - * adds extended format for `include` option to JSONAPI adapter [@beauby] + * adds extended format for `include` option to JsonApi adapter [@beauby] + * adds support for top level jsonapi member support [@beauby] diff --git a/docs/general/configuration_options.md b/docs/general/configuration_options.md index 2512bf469..5981d5f00 100644 --- a/docs/general/configuration_options.md +++ b/docs/general/configuration_options.md @@ -9,3 +9,5 @@ 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'`. diff --git a/lib/active_model/serializable_resource.rb b/lib/active_model/serializable_resource.rb index d3565f9a5..de5681bdf 100644 --- a/lib/active_model/serializable_resource.rb +++ b/lib/active_model/serializable_resource.rb @@ -1,7 +1,8 @@ require 'set' module ActiveModel class SerializableResource - ADAPTER_OPTION_KEYS = Set.new([:include, :fields, :adapter]) + ADAPTER_OPTION_KEYS = Set.new([:include, :fields, :adapter, + :jsonapi_toplevel_meta]) def initialize(resource, options = {}) @resource = resource diff --git a/lib/active_model/serializer/adapter/json_api.rb b/lib/active_model/serializer/adapter/json_api.rb index 1bd9ce526..1428a8616 100644 --- a/lib/active_model/serializer/adapter/json_api.rb +++ b/lib/active_model/serializer/adapter/json_api.rb @@ -16,11 +16,20 @@ def initialize(serializer, options = {}) def serializable_hash(options = nil) options ||= {} - if serializer.respond_to?(:each) - serializable_hash_for_collection(serializer, options) - else - serializable_hash_for_single_resource(serializer, 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] end + + hash end def fragment_cache(cached_hash, non_cached_hash) diff --git a/lib/active_model/serializer/configuration.rb b/lib/active_model/serializer/configuration.rb index 102c821e1..d696ad2c1 100644 --- a/lib/active_model/serializer/configuration.rb +++ b/lib/active_model/serializer/configuration.rb @@ -8,6 +8,8 @@ module Configuration base.config.array_serializer = ActiveModel::Serializer::ArraySerializer base.config.adapter = :flatten_json base.config.jsonapi_resource_type = :plural + base.config.jsonapi_toplevel_member = false + base.config.jsonapi_version = '1.0' end end end diff --git a/test/adapter/json_api/toplevel_jsonapi_test.rb b/test/adapter/json_api/toplevel_jsonapi_test.rb new file mode 100644 index 000000000..a95da1aea --- /dev/null +++ b/test/adapter/json_api/toplevel_jsonapi_test.rb @@ -0,0 +1,86 @@ +require 'test_helper' + +module ActiveModel + class Serializer + class Adapter + class JsonApi + class TopLevelJsonApiTest < Minitest::Test + 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') + @anonymous_post = Post.new(id: 43, title: 'Hello!!', body: 'Hello, world!!') + @comment = Comment.new(id: 1, body: 'ZOMG A COMMENT') + @post.comments = [@comment] + @post.blog = @blog + @anonymous_post.comments = [] + @anonymous_post.blog = nil + @comment.post = @post + @comment.author = nil + @post.author = @author + @anonymous_post.author = nil + @blog = Blog.new(id: 1, name: 'My Blog!!') + @blog.writer = @author + @blog.articles = [@post, @anonymous_post] + @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 + 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 + 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 + 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 + 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 + 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 + end + end + end + end + end + end +end