Skip to content

Commit 1844c16

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 Move docs from README to docs/ dir move links to json-api adapter & create Links class to hold links data
1 parent 72c2c9f commit 1844c16

File tree

7 files changed

+195
-0
lines changed

7 files changed

+195
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ tmp
2222
.ruby-version
2323
.ruby-gemset
2424
vendor/bundle
25+
tags

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ Features:
6565
CollectionSerializer for clarity, add ActiveModelSerializers.config.collection_serializer (@bf4)
6666
- [#1295](https://github.com/rails-api/active_model_serializers/pull/1295) Add config `serializer_lookup_enabled` that,
6767
when disabled, requires serializers to explicitly specified. (@trek)
68+
- [#1247](https://github.com/rails-api/active_model_serializers/pull/1247) Add top-level links (@beauby)
69+
* Add more tests and docs for top-level links (@leandrocp)
6870

6971
Fixes:
7072

docs/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ This is the documentation of ActiveModelSerializers, it's focused on the **0.10.
2323
- [How to add pagination links](howto/add_pagination_links.md)
2424
- [Using ActiveModelSerializers Outside Of Controllers](howto/outside_controller_use.md)
2525
- [Testing ActiveModelSerializers](howto/test.md)
26+
- [How to add top-level links](howto/add_top_level_links.md) (```JSON-API``` only)
2627

2728
## Integrations
2829

docs/howto/add_top_level_links.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# How to add top-level links
2+
3+
JsonApi supports a [links object](http://jsonapi.org/format/#document-links) to be specified at top-level, that you can specify in the `render`:
4+
5+
```ruby
6+
render json: @posts, links: { "self": "http://example.com/api/posts" }
7+
```
8+
9+
That's the result:
10+
11+
```json
12+
{
13+
"data": [
14+
{
15+
"type": "posts",
16+
"id": "1",
17+
"attributes": {
18+
"title": "JSON API is awesome!",
19+
"body": "You should be using JSON API",
20+
"created": "2015-05-22T14:56:29.000Z",
21+
"updated": "2015-05-22T14:56:28.000Z"
22+
}
23+
}
24+
],
25+
"links": {
26+
"self": "http://example.com/api/posts"
27+
}
28+
}
29+
```
30+
31+
This feature is specific to JsonApi, so you have to use the use the [JsonApi Adapter](https://github.com/rails-api/active_model_serializers/blob/master/docs/general/adapters.md#jsonapi)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
module ActiveModel
2+
class Serializer
3+
class Adapter
4+
class JsonApi < Adapter
5+
class Links
6+
def initialize(links = {})
7+
@links = links
8+
end
9+
10+
def serializable_hash
11+
@links
12+
end
13+
14+
def update(links = {})
15+
@links.update(links)
16+
end
17+
18+
def present?
19+
!@links.empty?
20+
end
21+
end
22+
end
23+
end
24+
end
25+
end

test/action_controller/serialization_test.rb

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,17 @@ def render_array_using_implicit_serializer_and_meta
4545
render json: @profiles, meta: { total: 10 }
4646
end
4747

48+
def render_array_using_implicit_serializer_and_links
49+
with_adapter ActiveModel::Serializer::Adapter::JsonApi do
50+
51+
@profiles = [
52+
Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
53+
]
54+
55+
render json: @profiles, links: { self: "http://example.com/api/profiles/1" }
56+
end
57+
end
58+
4859
def render_object_with_cache_enabled
4960
@comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
5061
@author = Author.new(id: 1, name: 'Joao Moura.')
@@ -254,6 +265,29 @@ def test_render_array_using_implicit_serializer_and_meta
254265
assert_equal expected.to_json, @response.body
255266
end
256267

268+
def test_render_array_using_implicit_serializer_and_links
269+
get :render_array_using_implicit_serializer_and_links
270+
271+
expected = {
272+
data: [
273+
{
274+
id: assigns(:profiles).first.id.to_s,
275+
type: "profiles",
276+
attributes: {
277+
name: "Name 1",
278+
description: "Description 1"
279+
}
280+
}
281+
],
282+
links: {
283+
self: "http://example.com/api/profiles/1"
284+
}
285+
}
286+
287+
assert_equal 'application/json', @response.content_type
288+
assert_equal expected.to_json, @response.body
289+
end
290+
257291
def test_render_with_cache_enable
258292
expected = {
259293
id: 1,
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
require 'test_helper'
2+
3+
module ActiveModel
4+
class Serializer
5+
class Adapter
6+
class JsonApi
7+
class TopLevelLinksTest < Minitest::Test
8+
URI = 'http://example.com'
9+
10+
def setup
11+
ActionController::Base.cache_store.clear
12+
@blog = Blog.new(id: 1,
13+
name: 'AMS Hints',
14+
writer: Author.new(id: 2, name: "Steve"),
15+
articles: [Post.new(id: 3, title: "AMS")])
16+
end
17+
18+
def load_adapter(paginated_collection, options = {})
19+
options = options.merge(adapter: :json_api)
20+
ActiveModel::SerializableResource.new(paginated_collection, options)
21+
end
22+
23+
def test_links_is_not_present_when_not_defined
24+
adapter = load_adapter(@blog)
25+
26+
expected = {
27+
:data => {
28+
:id => "1",
29+
:type => "blogs",
30+
:attributes => {
31+
:name => "AMS Hints"
32+
},
33+
:relationships => {
34+
:writer=> {:data => {:type => "authors", :id => "2"}},
35+
:articles => {:data => [{:type => "posts", :id => "3"}]}
36+
}
37+
}}
38+
39+
assert_equal expected, adapter.serializable_hash(@options)
40+
end
41+
42+
def test_links_is_present_when_defined
43+
adapter = load_adapter(@blog, {links: links})
44+
45+
expected = {
46+
:data => {
47+
:id => "1",
48+
:type => "blogs",
49+
:attributes => {
50+
:name => "AMS Hints"
51+
},
52+
:relationships => {
53+
:writer=> {:data => {:type => "authors", :id => "2"}},
54+
:articles => {:data => [{:type => "posts", :id => "3"}]}
55+
}
56+
},
57+
:links => {:self => "http://example.com/blogs/1"}
58+
}
59+
60+
assert_equal expected, adapter.serializable_hash(@options)
61+
end
62+
63+
def links
64+
{
65+
self: "#{URI}/blogs/1"
66+
}
67+
end
68+
69+
# def test_links_is_not_present_when_not_declared
70+
# serializer = AlternateBlogSerializer.new(@blog)
71+
# adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer)
72+
# expected = {
73+
# data: {
74+
# id: "1",
75+
# type: "blogs",
76+
# attributes: {
77+
# title: "AMS Hints"
78+
# }
79+
# }
80+
# }
81+
# assert_equal expected, adapter.as_json
82+
# end
83+
84+
# def test_links_is_not_present_on_flattenjson_adapter
85+
# serializer = AlternateBlogSerializer.new(@blog, :links => {:self => "/blogs/1"})
86+
# adapter = ActiveModel::Serializer::Adapter::FlattenJson.new(serializer)
87+
# expected = {:id=>1, :title=>"AMS Hints"}
88+
# assert_equal expected, adapter.as_json
89+
# end
90+
91+
# def test_links_is_not_present_on_json_adapter
92+
# serializer = AlternateBlogSerializer.new(@blog, :links => {:self => "/blogs/1"})
93+
# adapter = ActiveModel::Serializer::Adapter::Json.new(serializer)
94+
# expected = {:blog=>{:id=>1, :title=>"AMS Hints"}}
95+
# assert_equal expected, adapter.as_json
96+
# end
97+
end
98+
end
99+
end
100+
end
101+
end

0 commit comments

Comments
 (0)