Skip to content

Commit 9965abd

Browse files
author
Yohan Robert
committed
[skip ci] Update pagination and links doc
1 parent d39dd04 commit 9965abd

File tree

5 files changed

+415
-278
lines changed

5 files changed

+415
-278
lines changed

docs/README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ This is the documentation of ActiveModelSerializers, it's focused on the **0.10.
2222

2323
## How to
2424

25+
- [How to use ActiveModelSerializers outside of rails controllers](howto/outside_controller_use.md)
2526
- [How to add root key](howto/add_root_key.md)
26-
- [How to add pagination links](howto/add_pagination_links.md)
27-
- [How to add relationship links](howto/add_relationship_links.md)
28-
- [Using ActiveModelSerializers Outside Of Controllers](howto/outside_controller_use.md)
27+
- [How to add links](howto/add_links.md)
28+
- [How to handle pagination in JSON response](howto/handle_pagination.md)
2929
- [Testing ActiveModelSerializers](howto/test.md)
3030
- [Passing Arbitrary Options](howto/passing_arbitrary_options.md)
3131
- [How to serialize a Plain-Old Ruby Object (PORO)](howto/serialize_poro.md)

docs/howto/add_link.md

+337
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,337 @@
1+
[Back to Guides](../README.md)
2+
3+
# How to add links
4+
5+
`ActiveModelSerializers` offers you many ways to add links in your JSON reponse depending on the adapter you are using.
6+
7+
## JSON API adapter
8+
9+
The JSON API specification allows the usage of the `links` member for representing links in three cases:
10+
* [Top level links](http://jsonapi.org/format/#document-top-level)
11+
* [Resource link](http://jsonapi.org/format/#document-resource-object-links)
12+
* [Relationship links](http://jsonapi.org/format/#document-resource-object-relationships)
13+
14+
`ActiveModelSerializers` provides tools to handle these links.
15+
16+
### [Top level links](http://jsonapi.org/format/#document-top-level)
17+
18+
In order to provide top-level links, you will need to specify the `links` option to the serialization:
19+
20+
```ruby
21+
class UserSerializer < ActiveModel::Serializer
22+
attributes :id, :name
23+
end
24+
25+
user = User.new(id: 1, name: "John")
26+
links = {
27+
home: "https://www.example.com/"
28+
}
29+
resource = ActiveModelSerializers::SerializableResource.new(
30+
user,
31+
adapter: :json_api,
32+
links: links
33+
)
34+
resource.to_json
35+
```
36+
37+
This would result in:
38+
39+
```json
40+
{
41+
"links": {
42+
"home": "https://www.example.com/"
43+
},
44+
"data": {
45+
"id": "1",
46+
"type": "users",
47+
"attributes": {
48+
"name": "John"
49+
}
50+
}
51+
}
52+
```
53+
54+
When using Rails, you can add top-level links by providing the `links` option to `render` method:
55+
56+
```ruby
57+
class UserController < ActionController::Base
58+
def show
59+
user = User.new(id: 1, name: "John")
60+
links = {
61+
home: "https://www.example.com/"
62+
}
63+
render json: user, adapter: :json_api, links: links
64+
end
65+
end
66+
```
67+
68+
#### Pagination
69+
70+
`ActiveModelSerializers` will provides automatic pagination links for collections if use [Kaminari](https://github.com/amatsuda/kaminari)
71+
or [WillPaginate](https://github.com/mislav/will_paginate):
72+
73+
```ruby
74+
class UserController < ActionController::Base
75+
def kaminari
76+
users = User.all.to_a # .all.to_a used as example
77+
users = Kaminari.paginate_array(page).page(3).per(1)
78+
render json: users, adapter: :json_api
79+
end
80+
81+
def will_paginate
82+
users = User.all.to_a # .all.to_a used as example
83+
users = users.paginate(page: 3, per_page: 1)
84+
render json: users, adapter: :json_api
85+
end
86+
end
87+
```
88+
89+
Any of these actions would result in:
90+
```json
91+
{
92+
"data": [
93+
{
94+
"type": "users",
95+
"id": "3",
96+
"attributes": {
97+
"name": "John"
98+
}
99+
}
100+
],
101+
"links": {
102+
"self": "http://example.com/articles?page[number]=3&page[size]=1",
103+
"first": "http://example.com/articles?page[number]=1&page[size]=1",
104+
"prev": "http://example.com/articles?page[number]=2&page[size]=1",
105+
"next": "http://example.com/articles?page[number]=4&page[size]=1",
106+
"last": "http://example.com/articles?page[number]=13&page[size]=1"
107+
}
108+
}
109+
```
110+
111+
Note that `ActiveModelSerializers` pagination relies on a collection that has the methods `current_page`, `total_pages`, and `size`, such as are supported by both [Kaminari](https://github.com/amatsuda/kaminari) or [WillPaginate](https://github.com/mislav/will_paginate). If you want to have paginated links your collections but don't want to use neither Kaminari nor WillPaginate, make sure to define these methods.
112+
113+
### [Resource link](http://jsonapi.org/format/#document-resource-object-links)
114+
115+
You can use the `link` class method to define the links you need in the resource's primary data:
116+
117+
```ruby
118+
class UserSerializer < ActiveModel::Serializer
119+
attributes :id, :name
120+
121+
link(:self) { user_path(object.id) }
122+
link(:posts) { posts_path(user_id: object.id) }
123+
end
124+
125+
user = User.new(id: 1, name: "Kelly")
126+
resource = ActiveModelSerializers::SerializableResource.new(user, adapter: :json_api)
127+
resource.to_json
128+
```
129+
130+
This will result in:
131+
```json
132+
{
133+
"data": {
134+
"id": "1",
135+
"type": "users",
136+
"attributes": {
137+
"name": "Kelly"
138+
},
139+
"links": {
140+
"self": "/users/1",
141+
"posts": "/posts?user_id=1"
142+
}
143+
}
144+
}
145+
```
146+
147+
### [Relationship links](http://jsonapi.org/format/#document-resource-object-relationships)
148+
149+
You can use the `link` method wihtin you relationship block in order to define the links you need in the relationships:
150+
151+
```ruby
152+
class UserSerializer < ActiveModel::Serializer
153+
attributes :id, :name
154+
has_many :posts do
155+
link(:self) do
156+
user_posts_path(object.id) # Rails url helper automatically available
157+
end
158+
end
159+
end
160+
161+
user = User.new(id: 1, name: "Kelly", posts: [])
162+
resource = ActiveModelSerializers::SerializableResource.new(user, adapter: :json_api)
163+
resource.to_json
164+
```
165+
166+
Note that `user_posts_path` method is one of Rails' url helpers, which are automatically available within the `link` block if you are using Rails.
167+
168+
The previous snippet would result in:
169+
```json
170+
{
171+
"data": {
172+
"id": "1",
173+
"type": "users",
174+
"attributes": {
175+
"name": "Kelly"
176+
},
177+
"relationships": {
178+
"posts": {
179+
"data": [],
180+
"links": {
181+
"self": "users/1/posts"
182+
}
183+
}
184+
}
185+
}
186+
}
187+
```
188+
189+
If you only want the `links` member to appear you can set `include_data false` within the relationship block:
190+
191+
```ruby
192+
class UserSerializer < ActiveModel::Serializer
193+
attributes :id, :name
194+
has_many :posts do
195+
link(:self) do
196+
include_data false
197+
user_posts_path(object.id) # Rails url helper automatically available
198+
end
199+
end
200+
end
201+
202+
user = User.new(id: 1, name: "Kelly", posts: [ Post.new(id: 1) ])
203+
resource = ActiveModelSerializers::SerializableResource.new(user, adapter: :json_api)
204+
resource.to_json
205+
```
206+
207+
This would result in:
208+
209+
```json
210+
{
211+
"data": {
212+
"id": "1",
213+
"type": "users",
214+
"attributes": {
215+
"name": "Kelly"
216+
},
217+
"relationships": {
218+
"posts": {
219+
"links": {
220+
"self": "users/1/posts"
221+
}
222+
}
223+
}
224+
}
225+
}
226+
```
227+
228+
## JSON adapter
229+
230+
The `json` is not able to handle links defined by the `link` class method. However, you can either use the `meta` member or define a `links` attribute on the serializer.
231+
232+
### Via `meta`
233+
234+
```ruby
235+
class UserSerializer < ActiveModel::Serializer
236+
attributes :id, :name
237+
end
238+
user = User.new(id: 1, name: "John")
239+
meta = {
240+
links: {
241+
self: "/users/#{user.id}",
242+
posts: "/posts?user_id=#{user.id}"
243+
}
244+
}
245+
resource = ActiveModelSerializer::SerializableResource.new(
246+
user,
247+
adapter: :json,
248+
meta: meta
249+
)
250+
resource.to_json
251+
```
252+
253+
This would result in:
254+
255+
```json
256+
{
257+
"meta": {
258+
"links": {
259+
"self": "/users/1",
260+
"posts": "/posts?user_id=1"
261+
}
262+
},
263+
"user": {
264+
"id": "1",
265+
"name": "Example User",
266+
}
267+
}
268+
```
269+
270+
When using Rails, you can add links by providing the `meta` option to `render` method:
271+
272+
```ruby
273+
class UserController < ActionController::Base
274+
def show
275+
user = User.new(id: 1, name: "John")
276+
meta = {
277+
links: {
278+
self: "/users/#{user.id}",
279+
posts: "/posts?user_id=#{user.id}"
280+
}
281+
}
282+
render json: user, adapter: :json, meta: meta
283+
end
284+
end
285+
```
286+
287+
### Via an attribute
288+
289+
```ruby
290+
class UserSerializer < ActiveModel::Serializer
291+
attributes :id, :name, :links
292+
attribute :links do
293+
{
294+
self: "/users/#{object.id}",
295+
posts: "/posts?user_id=#{object.id}"
296+
}
297+
end
298+
end
299+
300+
user = User.new(id: 1, name: "John")
301+
resource = ActiveModelSerializer::SerializableResource.new(user, adapter: :json)
302+
resource.to_json
303+
```
304+
305+
This would result in:
306+
```json
307+
{
308+
"user": {
309+
"id": "1",
310+
"name": "Example User",
311+
"links": {
312+
"self": "/users/1",
313+
"posts": "/posts?user_id=1"
314+
}
315+
}
316+
}
317+
```
318+
319+
If you want to use the Rails' url/path helpers such as `user_path`, you need to `include` the `ActiveModelSerializers::SerializationContext::UrlHelpers` module into your serializer:
320+
321+
```ruby
322+
class UserSerializer < ActiveModel::Serializer
323+
include ActiveModelSerializers::SerializationContext::UrlHelpers
324+
325+
attributes :id, :name, :links
326+
attribute :links do
327+
{
328+
self: user_path(object.id),
329+
posts: posts_path(user_id: object.id)
330+
}
331+
end
332+
end
333+
```
334+
335+
## Attributes adapter
336+
337+
The only way to provide pagination with the `attributes` adapter is to define a `links` attribute [as described for the JSON adapter above](#via-an-attribute).

0 commit comments

Comments
 (0)