Skip to content

Commit 16f7512

Browse files
committed
Merge pull request #925 from benedikt/json-api
Updates JSON API Adapter to generate RC4 schema
2 parents 5f05944 + 2f6c431 commit 16f7512

14 files changed

+300
-230
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ AMS does this through two components: **serializers** and **adapters**.
88
Serializers describe _which_ attributes and relationships should be serialized.
99
Adapters describe _how_ attributes and relationships should be serialized.
1010

11-
By default AMS will use the JsonApi Adapter that follows RC3 of the format specified in [jsonapi.org/format](http://jsonapi.org/format).
11+
By default AMS will use the JsonApi Adapter that follows RC4 of the format specified in [jsonapi.org/format](http://jsonapi.org/format).
1212
Check how to change the adapter in the sections bellow.
1313

1414
# RELEASE CANDIDATE, PLEASE READ
@@ -178,7 +178,7 @@ end
178178

179179
#### JSONAPI
180180

181-
This adapter follows RC3 of the format specified in
181+
This adapter follows RC4 of the format specified in
182182
[jsonapi.org/format](http://jsonapi.org/format). It will include the associated
183183
resources in the `"included"` member when the resource names are included in the
184184
`include` option.

lib/active_model/serializer/adapter/json_api.rb

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def serializable_hash(options = {})
2929
end
3030
else
3131
@hash[:data] = attributes_for_serializer(serializer, @options)
32-
add_resource_links(@hash[:data], serializer)
32+
add_resource_relationships(@hash[:data], serializer)
3333
end
3434
@hash
3535
end
@@ -41,18 +41,18 @@ def fragment_cache(cached_hash, non_cached_hash)
4141

4242
private
4343

44-
def add_links(resource, name, serializers)
45-
resource[:links] ||= {}
46-
resource[:links][name] ||= { linkage: [] }
47-
resource[:links][name][:linkage] += serializers.map { |serializer| { type: serializer.type, id: serializer.id.to_s } }
44+
def add_relationships(resource, name, serializers)
45+
resource[:relationships] ||= {}
46+
resource[:relationships][name] ||= { data: [] }
47+
resource[:relationships][name][:data] += serializers.map { |serializer| { type: serializer.type, id: serializer.id.to_s } }
4848
end
4949

50-
def add_link(resource, name, serializer, val=nil)
51-
resource[:links] ||= {}
52-
resource[:links][name] = { linkage: nil }
50+
def add_relationship(resource, name, serializer, val=nil)
51+
resource[:relationships] ||= {}
52+
resource[:relationships][name] = { data: nil }
5353

5454
if serializer && serializer.object
55-
resource[:links][name][:linkage] = { type: serializer.type, id: serializer.id.to_s }
55+
resource[:relationships][name][:data] = { type: serializer.type, id: serializer.id.to_s }
5656
end
5757
end
5858

@@ -68,7 +68,7 @@ def add_included(resource_name, serializers, parent = nil)
6868
serializers.each do |serializer|
6969
attrs = attributes_for_serializer(serializer, @options)
7070

71-
add_resource_links(attrs, serializer, add_included: false)
71+
add_resource_relationships(attrs, serializer, add_included: false)
7272

7373
@hash[:included].push(attrs) unless @hash[:included].include?(attrs)
7474
end
@@ -85,26 +85,31 @@ def attributes_for_serializer(serializer, options)
8585
if serializer.respond_to?(:each)
8686
result = []
8787
serializer.each do |object|
88-
options[:fields] = @fieldset && @fieldset.fields_for(serializer)
89-
result << cache_check(object) do
90-
options[:required_fields] = [:id, :type]
91-
attributes = object.attributes(options)
92-
attributes[:id] = attributes[:id].to_s
93-
result << attributes
94-
end
88+
result << resource_object_for(object, options)
9589
end
9690
else
97-
options[:fields] = @fieldset && @fieldset.fields_for(serializer)
98-
options[:required_fields] = [:id, :type]
99-
result = cache_check(serializer) do
100-
result = serializer.attributes(options)
101-
result[:id] = result[:id].to_s
102-
result
103-
end
91+
result = resource_object_for(serializer, options)
10492
end
10593
result
10694
end
10795

96+
def resource_object_for(serializer, options)
97+
options[:fields] = @fieldset && @fieldset.fields_for(serializer)
98+
options[:required_fields] = [:id, :type]
99+
100+
cache_check(serializer) do
101+
attributes = serializer.attributes(options)
102+
103+
result = {
104+
id: attributes.delete(:id).to_s,
105+
type: attributes.delete(:type)
106+
}
107+
108+
result[:attributes] = attributes if attributes.any?
109+
result
110+
end
111+
end
112+
108113
def include_assoc?(assoc)
109114
return false unless @options[:include]
110115
check_assoc("#{assoc}$")
@@ -123,19 +128,19 @@ def check_assoc(assoc)
123128
end
124129
end
125130

126-
def add_resource_links(attrs, serializer, options = {})
131+
def add_resource_relationships(attrs, serializer, options = {})
127132
options[:add_included] = options.fetch(:add_included, true)
128133

129134
serializer.each_association do |name, association, opts|
130-
attrs[:links] ||= {}
135+
attrs[:relationships] ||= {}
131136

132137
if association.respond_to?(:each)
133-
add_links(attrs, name, association)
138+
add_relationships(attrs, name, association)
134139
else
135140
if opts[:virtual_value]
136-
add_link(attrs, name, nil, opts[:virtual_value])
141+
add_relationship(attrs, name, nil, opts[:virtual_value])
137142
else
138-
add_link(attrs, name, association)
143+
add_relationship(attrs, name, association)
139144
end
140145
end
141146

lib/active_model/serializer/adapter/json_api/fragment_cache.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ def fragment_cache(root, cached_hash, non_cached_hash)
1010
core_non_cached = non_cached_hash.first
1111
no_root_cache = cached_hash.delete_if {|key, value| key == core_cached[0] }
1212
no_root_non_cache = non_cached_hash.delete_if {|key, value| key == core_non_cached[0] }
13-
cached_resource = (core_cached[1]) ? core_cached[1].merge(core_non_cached[1]) : core_non_cached[1]
13+
cached_resource = (core_cached[1]) ? core_cached[1].deep_merge(core_non_cached[1]) : core_non_cached[1]
1414
hash = (root) ? { root => cached_resource } : cached_resource
15-
hash.merge no_root_non_cache.merge no_root_cache
15+
16+
hash.deep_merge no_root_non_cache.deep_merge no_root_cache
1617
end
1718

1819
end

test/action_controller/adapter_selector_test.rb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,12 @@ def test_render_using_adapter_override
3232

3333
expected = {
3434
data: {
35-
name: "Name 1",
36-
description: "Description 1",
3735
id: assigns(:profile).id.to_s,
38-
type: "profiles"
36+
type: "profiles",
37+
attributes: {
38+
name: "Name 1",
39+
description: "Description 1",
40+
}
3941
}
4042
}
4143

test/action_controller/json_api_linked_test.rb

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def test_render_resource_with_include
9191
response = JSON.parse(@response.body)
9292
assert response.key? 'included'
9393
assert_equal 1, response['included'].size
94-
assert_equal 'Steve K.', response['included'].first['name']
94+
assert_equal 'Steve K.', response['included'].first['attributes']['name']
9595
end
9696

9797
def test_render_resource_with_nested_has_many_include
@@ -101,29 +101,35 @@ def test_render_resource_with_nested_has_many_include
101101
{
102102
"id" => "1",
103103
"type" => "authors",
104-
"name" => "Steve K.",
105-
"links" => {
106-
"posts" => { "linkage" => [] },
107-
"roles" => { "linkage" => [{ "type" =>"roles", "id" => "1" }, { "type" =>"roles", "id" => "2" }] },
108-
"bio" => { "linkage" => nil }
104+
"attributes" => {
105+
"name" => "Steve K."
106+
},
107+
"relationships" => {
108+
"posts" => { "data" => [] },
109+
"roles" => { "data" => [{ "type" =>"roles", "id" => "1" }, { "type" =>"roles", "id" => "2" }] },
110+
"bio" => { "data" => nil }
109111
}
110112
}, {
111113
"id" => "1",
112114
"type" => "roles",
113-
"name" => "admin",
114-
"description" => nil,
115-
"slug" => "admin-1",
116-
"links" => {
117-
"author" => { "linkage" => { "type" =>"authors", "id" => "1" } }
115+
"attributes" => {
116+
"name" => "admin",
117+
"description" => nil,
118+
"slug" => "admin-1"
119+
},
120+
"relationships" => {
121+
"author" => { "data" => { "type" =>"authors", "id" => "1" } }
118122
}
119123
}, {
120124
"id" => "2",
121125
"type" => "roles",
122-
"name" => "colab",
123-
"description" => nil,
124-
"slug" => "colab-2",
125-
"links" => {
126-
"author" => { "linkage" => { "type" =>"authors", "id" => "1" } }
126+
"attributes" => {
127+
"name" => "colab",
128+
"description" => nil,
129+
"slug" => "colab-2"
130+
},
131+
"relationships" => {
132+
"author" => { "data" => { "type" =>"authors", "id" => "1" } }
127133
}
128134
}
129135
]
@@ -135,7 +141,7 @@ def test_render_resource_with_nested_include
135141
response = JSON.parse(@response.body)
136142
assert response.key? 'included'
137143
assert_equal 1, response['included'].size
138-
assert_equal 'Anonymous', response['included'].first['name']
144+
assert_equal 'Anonymous', response['included'].first['attributes']['name']
139145
end
140146

141147
def test_render_collection_without_include

test/action_controller/serialization_scope_name_test.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def render_new_user
2727

2828
def test_default_scope_name
2929
get :render_new_user
30-
assert_equal '{"data":{"admin?":false,"id":"1","type":"users"}}', @response.body
30+
assert_equal '{"data":{"id":"1","type":"users","attributes":{"admin?":false}}}', @response.body
3131
end
3232
end
3333

@@ -58,6 +58,6 @@ def render_new_user
5858

5959
def test_override_scope_name_with_controller
6060
get :render_new_user
61-
assert_equal '{"data":{"admin?":true,"id":"1","type":"users"}}', @response.body
61+
assert_equal '{"data":{"id":"1","type":"users","attributes":{"admin?":true}}}', @response.body
6262
end
6363
end

test/action_controller/serialization_test.rb

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -166,10 +166,12 @@ def test_render_using_default_root
166166

167167
expected = {
168168
data: {
169-
name: "Name 1",
170-
description: "Description 1",
171169
id: assigns(:profile).id.to_s,
172-
type: "profiles"
170+
type: "profiles",
171+
attributes: {
172+
name: "Name 1",
173+
description: "Description 1"
174+
}
173175
}
174176
}
175177

@@ -182,10 +184,12 @@ def test_render_using_custom_root_in_adapter_with_a_default
182184

183185
expected = {
184186
data: {
185-
name: "Name 1",
186-
description: "Description 1",
187187
id: assigns(:profile).id.to_s,
188-
type: "profiles"
188+
type: "profiles",
189+
attributes: {
190+
name: "Name 1",
191+
description: "Description 1"
192+
}
189193
}
190194
}
191195

@@ -217,10 +221,12 @@ def test_render_array_using_implicit_serializer_and_meta
217221
expected = {
218222
data: [
219223
{
220-
name: "Name 1",
221-
description: "Description 1",
222224
id: assigns(:profiles).first.id.to_s,
223-
type: "profiles"
225+
type: "profiles",
226+
attributes: {
227+
name: "Name 1",
228+
description: "Description 1"
229+
}
224230
}
225231
],
226232
meta: {

0 commit comments

Comments
 (0)