Skip to content

Commit c3c992c

Browse files
committed
Add support for top level jsonapi member.
1 parent 479146c commit c3c992c

File tree

6 files changed

+116
-6
lines changed

6 files changed

+116
-6
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@
1111
* remove root key option and split JSON adapter [@joaomdmoura]
1212
* adds FlattenJSON as default adapter [@joaomdmoura]
1313
* adds support for `pagination links` at top level of JsonApi adapter [@bacarini]
14-
* adds extended format for `include` option to JSONAPI adapter [@beauby]
14+
* adds extended format for `include` option to JsonApi adapter [@beauby]
15+
* adds support for top level jsonapi member support [@beauby]

docs/general/configuration_options.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ The following configuration options can be set on `ActiveModel::Serializer.confi
99
## JSON API
1010

1111
- `jsonapi_resource_type`: Whether the `type` attributes of resources should be singular or plural. Possible values: `:singular, :plural`. Default: `:plural`.
12+
- `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`.
13+
- `jsonapi_version`: The latest version of the spec the API conforms to. Used when `jsonapi_toplevel_member` is `true`. Default: `'1.0'`.

lib/active_model/serializable_resource.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
require 'set'
22
module ActiveModel
33
class SerializableResource
4-
ADAPTER_OPTION_KEYS = Set.new([:include, :fields, :adapter])
4+
ADAPTER_OPTION_KEYS = Set.new([:include, :fields, :adapter,
5+
:jsonapi_toplevel_version, :jsonapi_toplevel_meta])
56

67
def initialize(resource, options = {})
78
@resource = resource

lib/active_model/serializer/adapter/json_api.rb

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,20 @@ def initialize(serializer, options = {})
1616

1717
def serializable_hash(options = nil)
1818
options ||= {}
19-
if serializer.respond_to?(:each)
20-
serializable_hash_for_collection(serializer, options)
21-
else
22-
serializable_hash_for_single_resource(serializer, options)
19+
hash =
20+
if serializer.respond_to?(:each)
21+
serializable_hash_for_collection(serializer, options)
22+
else
23+
serializable_hash_for_single_resource(serializer, options)
24+
end
25+
26+
if ActiveModel::Serializer.config.jsonapi_toplevel_member
27+
hash[:jsonapi] = {}
28+
hash[:jsonapi][:version] = @options[:jsonapi_toplevel_version] || ActiveModel::Serializer.config.jsonapi_version
29+
hash[:jsonapi][:meta] = @options[:jsonapi_toplevel_meta] if @options[:jsonapi_toplevel_meta]
2330
end
31+
32+
hash
2433
end
2534

2635
def fragment_cache(cached_hash, non_cached_hash)

lib/active_model/serializer/configuration.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ module Configuration
88
base.config.array_serializer = ActiveModel::Serializer::ArraySerializer
99
base.config.adapter = :flatten_json
1010
base.config.jsonapi_resource_type = :plural
11+
base.config.jsonapi_toplevel_member = false
12+
base.config.jsonapi_version = '1.0'
1113
end
1214
end
1315
end
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
require 'test_helper'
2+
3+
module ActiveModel
4+
class Serializer
5+
class Adapter
6+
class JsonApi
7+
class TopLevelJsonApiTest < Minitest::Test
8+
def setup
9+
@author = Author.new(id: 1, name: 'Steve K.')
10+
@author.bio = nil
11+
@author.roles = []
12+
@blog = Blog.new(id: 23, name: 'AMS Blog')
13+
@post = Post.new(id: 42, title: 'New Post', body: 'Body')
14+
@anonymous_post = Post.new(id: 43, title: 'Hello!!', body: 'Hello, world!!')
15+
@comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
16+
@post.comments = [@comment]
17+
@post.blog = @blog
18+
@anonymous_post.comments = []
19+
@anonymous_post.blog = nil
20+
@comment.post = @post
21+
@comment.author = nil
22+
@post.author = @author
23+
@anonymous_post.author = nil
24+
@blog = Blog.new(id: 1, name: 'My Blog!!')
25+
@blog.writer = @author
26+
@blog.articles = [@post, @anonymous_post]
27+
@author.posts = []
28+
end
29+
30+
def with_config(option, value)
31+
old_value = ActiveModel::Serializer.config[option]
32+
ActiveModel::Serializer.config[option] = value
33+
yield
34+
ensure
35+
ActiveModel::Serializer.config[option] = old_value
36+
end
37+
38+
def test_disable_toplevel_jsonapi
39+
with_adapter :json_api do
40+
with_config(:jsonapi_toplevel_member, false) do
41+
hash = ActiveModel::SerializableResource.new(@post).serializable_hash
42+
assert_nil(hash[:jsonapi])
43+
end
44+
end
45+
end
46+
47+
def test_enable_toplevel_jsonapi
48+
with_adapter :json_api do
49+
with_config(:jsonapi_toplevel_member, true) do
50+
hash = ActiveModel::SerializableResource.new(@post).serializable_hash
51+
refute_nil(hash[:jsonapi])
52+
end
53+
end
54+
end
55+
56+
def test_default_toplevel_jsonapi_version
57+
with_adapter :json_api do
58+
with_config(:jsonapi_toplevel_member, true) do
59+
hash = ActiveModel::SerializableResource.new(@post).serializable_hash
60+
assert_equal('1.0', hash[:jsonapi][:version])
61+
end
62+
end
63+
end
64+
65+
def test_toplevel_jsonapi_custom_version
66+
with_adapter :json_api do
67+
with_config(:jsonapi_toplevel_member, true) do
68+
hash = ActiveModel::SerializableResource.new(@post, jsonapi_toplevel_version: 'custom').serializable_hash
69+
assert_equal('custom', hash[:jsonapi][:version])
70+
end
71+
end
72+
end
73+
74+
def test_toplevel_jsonapi_no_meta
75+
with_adapter :json_api do
76+
with_config(:jsonapi_toplevel_member, true) do
77+
hash = ActiveModel::SerializableResource.new(@post).serializable_hash
78+
assert_nil(hash[:jsonapi][:meta])
79+
end
80+
end
81+
end
82+
83+
def test_toplevel_jsonapi_meta
84+
with_adapter :json_api do
85+
with_config(:jsonapi_toplevel_member, true) do
86+
hash = ActiveModel::SerializableResource.new(@post, jsonapi_toplevel_meta: 'custom').serializable_hash
87+
assert_equal('custom', hash[:jsonapi][:meta])
88+
end
89+
end
90+
end
91+
end
92+
end
93+
end
94+
end
95+
end

0 commit comments

Comments
 (0)