Skip to content

Commit 1dcb3b3

Browse files
committed
Adds support for top-level links to JsonApi adapter
http://jsonapi.org/format/#document-top-level fix failing tests support for top-level links limited to jsonapi adapter
1 parent 03ddeee commit 1dcb3b3

File tree

9 files changed

+122
-3
lines changed

9 files changed

+122
-3
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ test/version_tmp
1919
tmp
2020
*.swp
2121
.ruby-version
22+
tags

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@
99
* adds cache support to attributes and associations [@joaomdmoura]
1010
* uses model name to determine the type [@lsylvester]
1111
* remove root key option and split JSON adapter [@joaomdmoura]
12-
* adds FlattenJSON as default adapter [@joaomdmoura]
12+
* adds FlattenJSON as default adapter [@joaomdmoura]
13+
* adds support for `links` at top level of JsonApi adapter [@leandrocp]

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,14 @@ render json: @post, meta: { total: 10 }, meta_key: "custom_meta"
138138

139139
`meta` will only be included in your response if you are using an Adapter that supports `root`, as JsonAPI and Json adapters, the default adapter (FlattenJson) doesn't have `root`.
140140

141+
### Links
142+
143+
A top-level `links` object may be specified in the `render` call:
144+
145+
```ruby
146+
render json: @post, links: { self: "/posts/1" }
147+
```
148+
141149
### Overriding association methods
142150

143151
If you want to override any association, you can use:

lib/active_model/serializer.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,15 @@ def self.root_name
105105
name.demodulize.underscore.sub(/_serializer$/, '') if name
106106
end
107107

108-
attr_accessor :object, :root, :meta, :meta_key, :scope
108+
attr_accessor :object, :root, :meta, :meta_key, :links, :scope
109109

110110
def initialize(object, options = {})
111111
@object = object
112112
@options = options
113113
@root = options[:root]
114114
@meta = options[:meta]
115115
@meta_key = options[:meta_key]
116+
@links = options[:links]
116117
@scope = options[:scope]
117118

118119
scope_name = options[:scope_name]

lib/active_model/serializer/adapter/json_api.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ def serializable_hash(options = nil)
3131
@hash[:data] = attributes_for_serializer(serializer, options)
3232
add_resource_relationships(@hash[:data], serializer)
3333
end
34+
@hash[:links] = attributes_for_top_level_links(serializer) if serializer.links
3435
@hash
3536
end
3637

@@ -157,6 +158,10 @@ def add_resource_relationships(attrs, serializer, options = {})
157158
end
158159
end
159160
end
161+
162+
def attributes_for_top_level_links(serializer)
163+
serializer.links
164+
end
160165
end
161166
end
162167
end

lib/active_model/serializer/array_serializer.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ class ArraySerializer
55
include Enumerable
66
delegate :each, to: :@objects
77

8-
attr_reader :root, :meta, :meta_key
8+
attr_reader :root, :meta, :meta_key, :links
99

1010
def initialize(objects, options = {})
1111
@root = options[:root]
@@ -24,6 +24,7 @@ def initialize(objects, options = {})
2424
end
2525
@meta = options[:meta]
2626
@meta_key = options[:meta_key]
27+
@links = options[:links]
2728
end
2829

2930
def json_key

test/action_controller/serialization_test.rb

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,17 @@ def render_array_using_implicit_serializer_and_meta
5858
end
5959
end
6060

61+
def render_array_using_implicit_serializer_and_links
62+
with_adapter ActiveModel::Serializer::Adapter::JsonApi do
63+
64+
@profiles = [
65+
Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
66+
]
67+
68+
render json: @profiles, links: { self: "/profiles/1" }
69+
end
70+
end
71+
6172
def render_object_with_cache_enabled
6273
@comment = Comment.new({ id: 1, body: 'ZOMG A COMMENT' })
6374
@author = Author.new(id: 1, name: 'Joao Moura.')
@@ -266,6 +277,29 @@ def test_render_array_using_implicit_serializer_and_meta
266277
assert_equal expected.to_json, @response.body
267278
end
268279

280+
def test_render_array_using_implicit_serializer_and_links
281+
get :render_array_using_implicit_serializer_and_links
282+
283+
expected = {
284+
data: [
285+
{
286+
id: assigns(:profiles).first.id.to_s,
287+
type: "profiles",
288+
attributes: {
289+
name: "Name 1",
290+
description: "Description 1"
291+
}
292+
}
293+
],
294+
links: {
295+
self: "/profiles/1"
296+
}
297+
}
298+
299+
assert_equal 'application/json', @response.content_type
300+
assert_equal expected.to_json, @response.body
301+
end
302+
269303
def test_render_with_cache_enable
270304
expected = {
271305
id: 1,

test/array_serializer_test.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ def test_meta_and_meta_key_attr_readers
4545
assert_equal @serializer.meta_key, "the meta key"
4646
end
4747

48+
def test_links_attr_reader
49+
@serializer = ArraySerializer.new([@comment, @post], :links => {"self" => "/array/1"})
50+
51+
assert_equal @serializer.links, {"self" => "/array/1"}
52+
end
53+
4854
def test_root_default
4955
@serializer = ArraySerializer.new([@comment, @post])
5056
assert_equal @serializer.root, nil

test/serializers/links_test.rb

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
require 'test_helper'
2+
3+
module ActiveModel
4+
class Serializer
5+
class LinksTest < Minitest::Test
6+
def setup
7+
ActionController::Base.cache_store.clear
8+
@blog = Blog.new(id: 1,
9+
name: 'AMS Hints',
10+
writer: Author.new(id: 2, name: "Steve"),
11+
articles: [Post.new(id: 3, title: "AMS")])
12+
end
13+
14+
def test_links_is_present_with_root
15+
serializer = AlternateBlogSerializer.new(@blog, :links => {:self => "/blogs/1"})
16+
adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer)
17+
expected = {
18+
data: {
19+
id: "1",
20+
type: "blogs",
21+
attributes: {
22+
title: "AMS Hints"
23+
}
24+
},
25+
links: {
26+
self: "/blogs/1"
27+
}
28+
}
29+
assert_equal expected, adapter.as_json
30+
end
31+
32+
def test_links_is_not_present_when_not_declared
33+
serializer = AlternateBlogSerializer.new(@blog)
34+
adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer)
35+
expected = {
36+
data: {
37+
id: "1",
38+
type: "blogs",
39+
attributes: {
40+
title: "AMS Hints"
41+
}
42+
}
43+
}
44+
assert_equal expected, adapter.as_json
45+
end
46+
47+
def test_links_is_not_present_on_flattenjson_adapter
48+
serializer = AlternateBlogSerializer.new(@blog, :links => {:self => "/blogs/1"})
49+
adapter = ActiveModel::Serializer::Adapter::FlattenJson.new(serializer)
50+
expected = {:id=>1, :title=>"AMS Hints"}
51+
assert_equal expected, adapter.as_json
52+
end
53+
54+
def test_links_is_not_present_on_json_adapter
55+
serializer = AlternateBlogSerializer.new(@blog, :links => {:self => "/blogs/1"})
56+
adapter = ActiveModel::Serializer::Adapter::Json.new(serializer)
57+
expected = {:blog=>{:id=>1, :title=>"AMS Hints"}}
58+
assert_equal expected, adapter.as_json
59+
end
60+
end
61+
end
62+
end

0 commit comments

Comments
 (0)