active_model_serializers 0.8.3 → 0.10.0.rc2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.travis.yml +18 -20
- data/CHANGELOG.md +8 -67
- data/CONTRIBUTING.md +31 -0
- data/Gemfile +14 -1
- data/{MIT-LICENSE.txt → LICENSE.txt} +3 -2
- data/README.md +169 -495
- data/Rakefile +6 -12
- data/active_model_serializers.gemspec +21 -19
- data/lib/action_controller/serialization.rb +36 -27
- data/lib/active_model/serializer/adapter/flatten_json.rb +12 -0
- data/lib/active_model/serializer/adapter/fragment_cache.rb +78 -0
- data/lib/active_model/serializer/adapter/json/fragment_cache.rb +15 -0
- data/lib/active_model/serializer/adapter/json.rb +50 -0
- data/lib/active_model/serializer/adapter/json_api/fragment_cache.rb +23 -0
- data/lib/active_model/serializer/adapter/json_api.rb +156 -0
- data/lib/active_model/serializer/adapter/null.rb +11 -0
- data/lib/active_model/serializer/adapter.rb +96 -0
- data/lib/active_model/serializer/array_serializer.rb +35 -0
- data/lib/active_model/serializer/configuration.rb +13 -0
- data/lib/active_model/serializer/fieldset.rb +40 -0
- data/lib/active_model/serializer/railtie.rb +8 -0
- data/lib/active_model/{serializers → serializer}/version.rb +1 -1
- data/lib/active_model/serializer.rb +177 -440
- data/lib/active_model_serializers.rb +10 -86
- data/lib/generators/serializer/USAGE +0 -3
- data/lib/generators/serializer/resource_override.rb +12 -0
- data/lib/generators/serializer/serializer_generator.rb +1 -6
- data/lib/generators/serializer/templates/serializer.rb +2 -13
- data/test/action_controller/adapter_selector_test.rb +53 -0
- data/test/action_controller/explicit_serializer_test.rb +134 -0
- data/test/action_controller/json_api_linked_test.rb +179 -0
- data/test/action_controller/rescue_from_test.rb +32 -0
- data/test/{serialization_scope_name_test.rb → action_controller/serialization_scope_name_test.rb} +7 -11
- data/test/action_controller/serialization_test.rb +383 -0
- data/test/adapter/fragment_cache_test.rb +27 -0
- data/test/adapter/json/belongs_to_test.rb +48 -0
- data/test/adapter/json/collection_test.rb +73 -0
- data/test/adapter/json/has_many_test.rb +36 -0
- data/test/adapter/json_api/belongs_to_test.rb +157 -0
- data/test/adapter/json_api/collection_test.rb +96 -0
- data/test/adapter/json_api/has_many_embed_ids_test.rb +45 -0
- data/test/adapter/json_api/has_many_explicit_serializer_test.rb +98 -0
- data/test/adapter/json_api/has_many_test.rb +110 -0
- data/test/adapter/json_api/has_one_test.rb +61 -0
- data/test/adapter/json_api/linked_test.rb +283 -0
- data/test/adapter/json_test.rb +34 -0
- data/test/adapter/null_test.rb +25 -0
- data/test/adapter_test.rb +43 -0
- data/test/array_serializer_test.rb +31 -63
- data/test/fixtures/poro.rb +230 -0
- data/test/generators/scaffold_controller_generator_test.rb +24 -0
- data/test/{generators_test.rb → generators/serializer_generator_test.rb} +2 -36
- data/test/serializers/adapter_for_test.rb +50 -0
- data/test/serializers/associations_test.rb +127 -0
- data/test/serializers/attribute_test.rb +38 -0
- data/test/serializers/attributes_test.rb +63 -0
- data/test/serializers/cache_test.rb +138 -0
- data/test/serializers/configuration_test.rb +15 -0
- data/test/serializers/fieldset_test.rb +26 -0
- data/test/serializers/meta_test.rb +107 -0
- data/test/serializers/options_test.rb +21 -0
- data/test/serializers/serializer_for_test.rb +65 -0
- data/test/serializers/urls_test.rb +26 -0
- data/test/test_helper.rb +28 -16
- metadata +109 -43
- data/DESIGN.textile +0 -586
- data/Gemfile.edge +0 -9
- data/bench/perf.rb +0 -43
- data/cruft.md +0 -19
- data/lib/active_model/array_serializer.rb +0 -104
- data/lib/active_model/serializer/associations.rb +0 -233
- data/lib/active_record/serializer_override.rb +0 -16
- data/lib/generators/resource_override.rb +0 -13
- data/test/association_test.rb +0 -592
- data/test/caching_test.rb +0 -96
- data/test/no_serialization_scope_test.rb +0 -34
- data/test/serialization_test.rb +0 -392
- data/test/serializer_support_test.rb +0 -51
- data/test/serializer_test.rb +0 -1465
- data/test/test_fakes.rb +0 -217
data/README.md
CHANGED
@@ -1,655 +1,329 @@
|
|
1
|
-
|
1
|
+
# ActiveModel::Serializers
|
2
2
|
|
3
|
-
|
3
|
+
[](https://travis-ci.org/rails-api/active_model_serializers)
|
4
4
|
|
5
|
-
|
6
|
-
encapsulate serialization of `ActiveModel` objects, including `ActiveRecord`
|
7
|
-
objects.
|
5
|
+
ActiveModel::Serializers brings convention over configuration to your JSON generation.
|
8
6
|
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
AMS does this through two components: **serializers** and **adapters**.
|
8
|
+
Serializers describe _which_ attributes and relationships should be serialized.
|
9
|
+
Adapters describe _how_ attributes and relationships should be serialized.
|
12
10
|
|
13
|
-
|
14
|
-
|
11
|
+
By default AMS will use the **Json Adapter**. But we strongly advise you to use JsonApi Adapter that follows 1.0 of the format specified in [jsonapi.org/format](http://jsonapi.org/format).
|
12
|
+
Check how to change the adapter in the sections bellow.
|
15
13
|
|
16
|
-
#
|
14
|
+
# RELEASE CANDIDATE, PLEASE READ
|
17
15
|
|
18
|
-
|
19
|
-
|
16
|
+
This is the master branch of AMS. It will become the `0.10.0` release when it's
|
17
|
+
ready. Currently this is a release candidate. This is **not** backward
|
18
|
+
compatible with `0.9.0` or `0.8.0`.
|
20
19
|
|
21
|
-
|
22
|
-
|
23
|
-
```
|
24
|
-
|
25
|
-
Then, install it on the command line:
|
26
|
-
|
27
|
-
```
|
28
|
-
$ bundle install
|
29
|
-
```
|
20
|
+
`0.10.x` will be based on the `0.8.0` code, but with a more flexible
|
21
|
+
architecture. We'd love your help. [Learn how you can help here.](https://github.com/rails-api/active_model_serializers/blob/master/CONTRIBUTING.md)
|
30
22
|
|
31
|
-
|
23
|
+
## Example
|
32
24
|
|
33
|
-
|
34
|
-
|
25
|
+
Given two models, a `Post(title: string, body: text)` and a
|
26
|
+
`Comment(name:string, body:text, post_id:integer)`, you will have two
|
27
|
+
serializers:
|
35
28
|
|
36
|
-
```
|
37
|
-
|
38
|
-
|
29
|
+
```ruby
|
30
|
+
class PostSerializer < ActiveModel::Serializer
|
31
|
+
cache key: 'posts', expires_in: 3.hours
|
32
|
+
attributes :title, :body
|
39
33
|
|
40
|
-
|
41
|
-
your new model. You can also generate a serializer for an existing model with
|
42
|
-
the serializer generator:
|
34
|
+
has_many :comments
|
43
35
|
|
36
|
+
url :post
|
37
|
+
end
|
44
38
|
```
|
45
|
-
$ rails g serializer post
|
46
|
-
```
|
47
|
-
|
48
|
-
### Support for PORO's and other ORM's.
|
49
|
-
|
50
|
-
Currently `ActiveModel::Serializers` adds serialization support to all models
|
51
|
-
that descend from `ActiveRecord` or include `Mongoid::Document`. If you are
|
52
|
-
using another ORM, or if you are using objects that are `ActiveModel`
|
53
|
-
compliant but do not descend from `ActiveRecord` or include
|
54
|
-
`Mongoid::Document`, you must add an include statement for
|
55
|
-
`ActiveModel::SerializerSupport` to make models serializable. If you
|
56
|
-
also want to make collections serializable, you should include
|
57
|
-
`ActiveModel::ArraySerializerSupport` into your ORM's
|
58
|
-
relation/criteria class.
|
59
|
-
|
60
|
-
# ActiveModel::Serializer
|
61
39
|
|
62
|
-
|
40
|
+
and
|
63
41
|
|
64
|
-
|
42
|
+
```ruby
|
43
|
+
class CommentSerializer < ActiveModel::Serializer
|
44
|
+
attributes :name, :body
|
65
45
|
|
66
|
-
|
67
|
-
for a serializer for the object and use it if available.
|
46
|
+
belongs_to :post
|
68
47
|
|
69
|
-
|
70
|
-
class PostsController < ApplicationController
|
71
|
-
def show
|
72
|
-
@post = Post.find(params[:id])
|
73
|
-
render :json => @post
|
74
|
-
end
|
48
|
+
url [:post, :comment]
|
75
49
|
end
|
76
50
|
```
|
77
51
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
This also works with `respond_with`, which uses `to_json` under the hood. Also
|
82
|
-
note that any options passed to `render :json` will be passed to your
|
83
|
-
serializer and available as `@options` inside.
|
84
|
-
|
85
|
-
To specify a custom serializer for an object, there are 2 options:
|
86
|
-
|
87
|
-
#### 1. Specify the serializer in your model:
|
52
|
+
Generally speaking, you as a user of AMS will write (or generate) these
|
53
|
+
serializer classes. If you want to use a different adapter, such as a JsonApi, you can
|
54
|
+
change this in an initializer:
|
88
55
|
|
89
56
|
```ruby
|
90
|
-
|
91
|
-
def active_model_serializer
|
92
|
-
FancyPostSerializer
|
93
|
-
end
|
94
|
-
end
|
57
|
+
ActiveModel::Serializer.config.adapter = ActiveModel::Serializer::Adapter::JsonApi
|
95
58
|
```
|
96
59
|
|
97
|
-
|
60
|
+
or
|
98
61
|
|
99
62
|
```ruby
|
100
|
-
|
63
|
+
ActiveModel::Serializer.config.adapter = :json_api
|
101
64
|
```
|
102
65
|
|
103
|
-
|
66
|
+
You won't need to implement an adapter unless you wish to use a new format or
|
67
|
+
media type with AMS.
|
104
68
|
|
105
|
-
|
106
|
-
use `ActiveModel::ArraySerializer` (included in this project) as the base serializer,
|
107
|
-
and the individual `Serializer` for the objects contained in that array.
|
69
|
+
If you would like the key in the outputted JSON to be different from its name in ActiveRecord, you can use the :key option to customize it:
|
108
70
|
|
109
71
|
```ruby
|
110
72
|
class PostSerializer < ActiveModel::Serializer
|
111
|
-
attributes :
|
112
|
-
end
|
73
|
+
attributes :id, :body
|
113
74
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
render :json => @posts
|
118
|
-
end
|
75
|
+
# look up :subject on the model, but use +title+ in the JSON
|
76
|
+
attribute :subject, :key => :title
|
77
|
+
has_many :comments
|
119
78
|
end
|
120
79
|
```
|
121
80
|
|
122
|
-
|
123
|
-
|
124
|
-
```json
|
125
|
-
{
|
126
|
-
"posts":
|
127
|
-
[
|
128
|
-
{ "title": "Post 1", "body": "Hello!" },
|
129
|
-
{ "title": "Post 2", "body": "Goodbye!" }
|
130
|
-
]
|
131
|
-
}
|
132
|
-
```
|
133
|
-
|
134
|
-
By default, the root element is the name of the controller. For example, `PostsController`
|
135
|
-
generates a root element "posts". To change it:
|
81
|
+
In your controllers, when you use `render :json`, Rails will now first search
|
82
|
+
for a serializer for the object and use it if available.
|
136
83
|
|
137
84
|
```ruby
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
You may disable the root element for arrays at the top level, which will result in
|
142
|
-
more concise json. See the next section for ways on how to do this. Disabling the
|
143
|
-
root element of the array with any of those methods will produce
|
144
|
-
|
145
|
-
```json
|
146
|
-
[
|
147
|
-
{ "title": "Post 1", "body": "Hello!" },
|
148
|
-
{ "title": "Post 2", "body": "Goodbye!" }
|
149
|
-
]
|
150
|
-
```
|
151
|
-
|
152
|
-
To specify a custom serializer for the items within an array:
|
85
|
+
class PostsController < ApplicationController
|
86
|
+
def show
|
87
|
+
@post = Post.find(params[:id])
|
153
88
|
|
154
|
-
|
155
|
-
|
89
|
+
render json: @post
|
90
|
+
end
|
91
|
+
end
|
156
92
|
```
|
157
93
|
|
158
|
-
|
159
|
-
|
160
|
-
You have 4 options to disable the root element, each with a slightly different scope:
|
161
|
-
|
162
|
-
#### 1. Disable root globally for all, or per class
|
94
|
+
In this case, Rails will look for a serializer named `PostSerializer`, and if
|
95
|
+
it exists, use it to serialize the `Post`.
|
163
96
|
|
164
|
-
|
97
|
+
### Specify a serializer
|
165
98
|
|
166
|
-
|
167
|
-
ActiveSupport.on_load(:active_model_serializers) do
|
168
|
-
# Disable for all serializers (except ArraySerializer)
|
169
|
-
ActiveModel::Serializer.root = false
|
170
|
-
|
171
|
-
# Disable for ArraySerializer
|
172
|
-
ActiveModel::ArraySerializer.root = false
|
173
|
-
end
|
174
|
-
```
|
99
|
+
If you wish to use a serializer other than the default, you can explicitly pass it to the renderer.
|
175
100
|
|
176
|
-
####
|
101
|
+
#### 1. For a resource:
|
177
102
|
|
178
103
|
```ruby
|
179
|
-
render :
|
104
|
+
render json: @post, serializer: PostPreviewSerializer
|
180
105
|
```
|
181
106
|
|
182
|
-
####
|
107
|
+
#### 2. For an array resource:
|
183
108
|
|
184
109
|
```ruby
|
185
|
-
|
186
|
-
|
187
|
-
|
110
|
+
# Use the default `ArraySerializer`, which will use `each_serializer` to
|
111
|
+
# serialize each element
|
112
|
+
render json: @posts, each_serializer: PostPreviewSerializer
|
188
113
|
|
189
|
-
#
|
190
|
-
render :
|
114
|
+
# Or, you can explicitly provide the collection serializer as well
|
115
|
+
render json: @posts, serializer: PaginatedSerializer, each_serializer: PostPreviewSerializer
|
191
116
|
```
|
192
117
|
|
193
|
-
|
118
|
+
### Meta
|
194
119
|
|
195
|
-
If you
|
196
|
-
|
197
|
-
One of the options may be `root: false`
|
120
|
+
If you want a `meta` attribute in your response, specify it in the `render`
|
121
|
+
call:
|
198
122
|
|
199
123
|
```ruby
|
200
|
-
|
201
|
-
{
|
202
|
-
root: false
|
203
|
-
}
|
204
|
-
end
|
124
|
+
render json: @post, meta: { total: 10 }
|
205
125
|
```
|
206
126
|
|
207
|
-
|
208
|
-
|
209
|
-
If you find that your project is already relying on the old rails to_json
|
210
|
-
change `render :json` to `render :json => @your_object.to_json`.
|
211
|
-
|
212
|
-
# Attributes and Associations
|
213
|
-
|
214
|
-
Once you have a serializer, you can specify which attributes and associations
|
215
|
-
you would like to include in the serialized form.
|
127
|
+
The key can be customized using `meta_key` option.
|
216
128
|
|
217
129
|
```ruby
|
218
|
-
|
219
|
-
attributes :id, :title, :body
|
220
|
-
has_many :comments
|
221
|
-
end
|
130
|
+
render json: @post, meta: { total: 10 }, meta_key: "custom_meta"
|
222
131
|
```
|
223
132
|
|
224
|
-
|
133
|
+
`meta` will only be included in your response if there's a root. For instance,
|
134
|
+
it won't be included in array responses.
|
225
135
|
|
226
|
-
|
227
|
-
object you passed to `render :json`. It uses
|
228
|
-
`read_attribute_for_serialization`, which `ActiveRecord` objects implement as a
|
229
|
-
regular attribute lookup.
|
136
|
+
### Root key
|
230
137
|
|
231
|
-
|
232
|
-
|
233
|
-
include properties beyond the simple attributes of the model. For example:
|
138
|
+
If you want to define a custom root for your response, specify it in the `render`
|
139
|
+
call:
|
234
140
|
|
235
141
|
```ruby
|
236
|
-
|
237
|
-
attributes :first_name, :last_name, :full_name
|
238
|
-
|
239
|
-
def full_name
|
240
|
-
"#{object.first_name} #{object.last_name}"
|
241
|
-
end
|
242
|
-
end
|
142
|
+
render json: @post, root: "articles"
|
243
143
|
```
|
244
144
|
|
245
|
-
|
246
|
-
serialized as `object`.
|
247
|
-
|
248
|
-
You can also access the `current_user` method, which provides an
|
249
|
-
authorization context to your serializer. By default, the context
|
250
|
-
is the current user of your application, but this
|
251
|
-
[can be customized](#customizing-scope).
|
145
|
+
### Overriding association methods
|
252
146
|
|
253
|
-
|
254
|
-
`include_[ATTRIBUTE]?` to determine whether a particular attribute should be
|
255
|
-
included in the output. This is typically used to customize output
|
256
|
-
based on `current_user`. For example:
|
147
|
+
If you want to override any association, you can use:
|
257
148
|
|
258
149
|
```ruby
|
259
150
|
class PostSerializer < ActiveModel::Serializer
|
260
|
-
attributes :id, :
|
261
|
-
|
262
|
-
def include_author?
|
263
|
-
current_user.admin?
|
264
|
-
end
|
265
|
-
end
|
266
|
-
```
|
267
|
-
|
268
|
-
The type of a computed attribute (like :full_name above) is not easily
|
269
|
-
calculated without some sophisticated static code analysis. To specify the
|
270
|
-
type of a computed attribute:
|
151
|
+
attributes :id, :body
|
271
152
|
|
272
|
-
|
273
|
-
class PersonSerializer < ActiveModel::Serializer
|
274
|
-
attributes :first_name, :last_name, {:full_name => :string}
|
153
|
+
has_many :comments
|
275
154
|
|
276
|
-
def
|
277
|
-
|
155
|
+
def comments
|
156
|
+
object.comments.active
|
278
157
|
end
|
279
158
|
end
|
280
159
|
```
|
281
160
|
|
282
|
-
|
283
|
-
|
161
|
+
### Overriding attribute methods
|
162
|
+
|
163
|
+
If you want to override any attribute, you can use:
|
284
164
|
|
285
165
|
```ruby
|
286
166
|
class PostSerializer < ActiveModel::Serializer
|
287
167
|
attributes :id, :body
|
288
168
|
|
289
|
-
# look up :subject on the model, but use +title+ in the JSON
|
290
|
-
attribute :subject, :key => :title
|
291
169
|
has_many :comments
|
292
|
-
end
|
293
|
-
```
|
294
|
-
|
295
|
-
If you would like to add meta information to the outputted JSON, use the `:meta`
|
296
|
-
option:
|
297
170
|
|
298
|
-
|
299
|
-
|
171
|
+
def body
|
172
|
+
object.body.downcase
|
173
|
+
end
|
174
|
+
end
|
300
175
|
```
|
301
176
|
|
302
|
-
|
177
|
+
### Built in Adapters
|
303
178
|
|
304
|
-
|
305
|
-
{
|
306
|
-
"meta": { "total": 10 },
|
307
|
-
"posts": [
|
308
|
-
{ "title": "Post 1", "body": "Hello!" },
|
309
|
-
{ "title": "Post 2", "body": "Goodbye!" }
|
310
|
-
]
|
311
|
-
}
|
312
|
-
```
|
179
|
+
#### JSONAPI
|
313
180
|
|
314
|
-
|
181
|
+
This adapter follows RC4 of the format specified in
|
182
|
+
[jsonapi.org/format](http://jsonapi.org/format). It will include the associated
|
183
|
+
resources in the `"included"` member when the resource names are included in the
|
184
|
+
`include` option.
|
315
185
|
|
316
186
|
```ruby
|
317
|
-
render
|
187
|
+
render @posts, include: ['authors', 'comments']
|
188
|
+
# or
|
189
|
+
render @posts, include: 'authors,comments'
|
318
190
|
```
|
319
191
|
|
320
|
-
|
321
|
-
|
322
|
-
```json
|
323
|
-
{
|
324
|
-
"meta_object": { "total": 10 },
|
325
|
-
"posts": [
|
326
|
-
{ "title": "Post 1", "body": "Hello!" },
|
327
|
-
{ "title": "Post 2", "body": "Goodbye!" }
|
328
|
-
]
|
329
|
-
}
|
330
|
-
```
|
192
|
+
## Installation
|
331
193
|
|
332
|
-
|
333
|
-
completely override the `attributes` method to return the hash you need:
|
194
|
+
Add this line to your application's Gemfile:
|
334
195
|
|
335
|
-
```
|
336
|
-
|
337
|
-
attributes :first_name, :last_name
|
338
|
-
|
339
|
-
def attributes
|
340
|
-
hash = super
|
341
|
-
if current_user.admin?
|
342
|
-
hash["ssn"] = object.ssn
|
343
|
-
hash["secret"] = object.mothers_maiden_name
|
344
|
-
end
|
345
|
-
hash
|
346
|
-
end
|
347
|
-
end
|
196
|
+
```
|
197
|
+
gem 'active_model_serializers'
|
348
198
|
```
|
349
199
|
|
350
|
-
|
200
|
+
And then execute:
|
351
201
|
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
and use it to serialize the comment.
|
202
|
+
```
|
203
|
+
$ bundle
|
204
|
+
```
|
356
205
|
|
357
|
-
|
358
|
-
You can customize this behavior by implementing a method with the name of the
|
359
|
-
association and returning a different Array. Often, you will do this to
|
360
|
-
customize the objects returned based on the current user.
|
206
|
+
## Creating a Serializer
|
361
207
|
|
362
|
-
|
363
|
-
|
364
|
-
attributes :id, :title, :body
|
365
|
-
has_many :comments
|
208
|
+
The easiest way to create a new serializer is to generate a new resource, which
|
209
|
+
will generate a serializer at the same time:
|
366
210
|
|
367
|
-
|
368
|
-
|
369
|
-
object.comments.where(:created_by => current_user)
|
370
|
-
end
|
371
|
-
end
|
211
|
+
```
|
212
|
+
$ rails g resource post title:string body:string
|
372
213
|
```
|
373
214
|
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
```ruby
|
378
|
-
class PostSerializer < ActiveModel::Serializer
|
379
|
-
attributes :id, :title, :body
|
215
|
+
This will generate a serializer in `app/serializers/post_serializer.rb` for
|
216
|
+
your new model. You can also generate a serializer for an existing model with
|
217
|
+
the serializer generator:
|
380
218
|
|
381
|
-
|
382
|
-
|
383
|
-
end
|
219
|
+
```
|
220
|
+
$ rails g serializer post
|
384
221
|
```
|
385
222
|
|
386
|
-
|
387
|
-
|
388
|
-
should be included in the output. For example:
|
223
|
+
The generated seralizer will contain basic `attributes` and
|
224
|
+
`has_many`/`has_one`/`belongs_to` declarations, based on the model. For example:
|
389
225
|
|
390
226
|
```ruby
|
391
227
|
class PostSerializer < ActiveModel::Serializer
|
392
|
-
attributes :
|
228
|
+
attributes :title, :body
|
229
|
+
|
393
230
|
has_many :comments
|
231
|
+
has_one :author
|
394
232
|
|
395
|
-
|
396
|
-
!object.comments_disabled?
|
397
|
-
end
|
233
|
+
url :post
|
398
234
|
end
|
399
235
|
```
|
400
236
|
|
401
|
-
|
402
|
-
override `include_associations!` to specify which associations should be included:
|
237
|
+
and
|
403
238
|
|
404
239
|
```ruby
|
405
|
-
class
|
406
|
-
attributes :
|
407
|
-
has_one :author
|
408
|
-
has_many :comments
|
240
|
+
class CommentSerializer < ActiveModel::Serializer
|
241
|
+
attributes :name, :body
|
409
242
|
|
410
|
-
|
411
|
-
include! :author if current_user.admin?
|
412
|
-
include! :comments unless object.comments_disabled?
|
413
|
-
end
|
414
|
-
end
|
415
|
-
```
|
416
|
-
|
417
|
-
You may also use the `:serializer` option to specify a custom serializer class and the `:polymorphic` option to specify an association that is polymorphic (STI), e.g.:
|
243
|
+
belongs_to :post_id
|
418
244
|
|
419
|
-
|
420
|
-
|
421
|
-
has_one :reviewer, :polymorphic => true
|
245
|
+
url [:post, :comment]
|
246
|
+
end
|
422
247
|
```
|
423
248
|
|
424
|
-
|
249
|
+
The attribute names are a **whitelist** of attributes to be serialized.
|
425
250
|
|
426
|
-
|
251
|
+
The `has_many`, `has_one`, and `belongs_to` declarations describe relationships between
|
252
|
+
resources. By default, when you serialize a `Post`, you will get its `Comment`s
|
253
|
+
as well.
|
427
254
|
|
428
|
-
|
429
|
-
you have a post, the outputted JSON will look like:
|
255
|
+
You may also use the `:serializer` option to specify a custom serializer class, for example:
|
430
256
|
|
431
|
-
```
|
432
|
-
|
433
|
-
"post": {
|
434
|
-
"id": 1,
|
435
|
-
"title": "New post",
|
436
|
-
"body": "A body!",
|
437
|
-
"comments": [
|
438
|
-
{ "id": 1, "body": "what a dumb post" }
|
439
|
-
]
|
440
|
-
}
|
441
|
-
}
|
257
|
+
```ruby
|
258
|
+
has_many :comments, serializer: CommentPreviewSerializer
|
442
259
|
```
|
443
260
|
|
444
|
-
|
445
|
-
|
446
|
-
flexible from a performance standpoint and avoids wasteful duplication.
|
261
|
+
The `url` declaration describes which named routes to use while generating URLs
|
262
|
+
for your JSON. Not every adapter will require URLs.
|
447
263
|
|
448
|
-
|
264
|
+
## Caching
|
449
265
|
|
450
|
-
```
|
451
|
-
|
452
|
-
|
266
|
+
To cache a serializer, call ```cache``` and pass its options.
|
267
|
+
The options are the same options of ```ActiveSupport::Cache::Store```, plus
|
268
|
+
a ```key``` option that will be the prefix of the object cache
|
269
|
+
on a pattern ```"#{key}/#{object.id}-#{object.updated_at}"```.
|
453
270
|
|
454
|
-
|
455
|
-
has_many :comments
|
456
|
-
end
|
457
|
-
```
|
271
|
+
The cache support is optimized to use the cached object in multiple request. An object cached on a ```show``` request will be reused at the ```index```. If there is a relationship with another cached serializer it will also be created and reused automatically.
|
458
272
|
|
459
|
-
|
460
|
-
|
461
|
-
```json
|
462
|
-
{
|
463
|
-
"post": {
|
464
|
-
"id": 1,
|
465
|
-
"title": "New post",
|
466
|
-
"body": "A body!",
|
467
|
-
"comment_ids": [ 1, 2, 3 ]
|
468
|
-
}
|
469
|
-
}
|
470
|
-
```
|
273
|
+
**[NOTE] Every object is individually cached.**
|
471
274
|
|
472
|
-
|
275
|
+
**[NOTE] The cache is automatically expired after update an object but it's not deleted.**
|
473
276
|
|
474
277
|
```ruby
|
475
|
-
|
476
|
-
attributes :id, :title, :body
|
477
|
-
|
478
|
-
has_many :comments, embed: :objects
|
479
|
-
has_many :tags, embed: :ids
|
480
|
-
end
|
481
|
-
```
|
482
|
-
|
483
|
-
The JSON will look like this:
|
484
|
-
|
485
|
-
```json
|
486
|
-
{
|
487
|
-
"post": {
|
488
|
-
"id": 1,
|
489
|
-
"title": "New post",
|
490
|
-
"body": "A body!",
|
491
|
-
"comments": [
|
492
|
-
{ "id": 1, "body": "what a dumb post" }
|
493
|
-
],
|
494
|
-
"tag_ids": [ 1, 2, 3 ]
|
495
|
-
}
|
496
|
-
}
|
278
|
+
cache(options = nil) # options: ```{key, expires_in, compress, force, race_condition_ttl}```
|
497
279
|
```
|
498
280
|
|
499
|
-
|
500
|
-
alongside the main object. This makes it easier to process the entire package
|
501
|
-
of data without having to recursively scan the tree looking for embedded
|
502
|
-
information. It also ensures that associations that are shared between several
|
503
|
-
objects (like tags), are only delivered once for the entire payload.
|
504
|
-
|
505
|
-
You can specify that the data be included like this:
|
281
|
+
Take the example bellow:
|
506
282
|
|
507
283
|
```ruby
|
508
284
|
class PostSerializer < ActiveModel::Serializer
|
509
|
-
|
285
|
+
cache key: 'post', expires_in: 3.hours
|
286
|
+
attributes :title, :body
|
510
287
|
|
511
|
-
attributes :id, :title, :body
|
512
288
|
has_many :comments
|
513
|
-
end
|
514
|
-
```
|
515
|
-
|
516
|
-
Assuming that the comments also `has_many :tags`, you will get a JSON like
|
517
|
-
this:
|
518
|
-
|
519
|
-
```json
|
520
|
-
{
|
521
|
-
"post": {
|
522
|
-
"id": 1,
|
523
|
-
"title": "New post",
|
524
|
-
"body": "A body!",
|
525
|
-
"comment_ids": [ 1, 2 ]
|
526
|
-
},
|
527
|
-
"comments": [
|
528
|
-
{ "id": 1, "body": "what a dumb post", "tag_ids": [ 1, 2 ] },
|
529
|
-
{ "id": 2, "body": "i liked it", "tag_ids": [ 1, 3 ] },
|
530
|
-
],
|
531
|
-
"tags": [
|
532
|
-
{ "id": 1, "name": "short" },
|
533
|
-
{ "id": 2, "name": "whiny" },
|
534
|
-
{ "id": 3, "name": "happy" }
|
535
|
-
]
|
536
|
-
}
|
537
|
-
```
|
538
289
|
|
539
|
-
|
540
|
-
used to reference them:
|
541
|
-
|
542
|
-
```ruby
|
543
|
-
class PostSerializer < ActiveModel::Serializer
|
544
|
-
embed :ids, :include => true
|
545
|
-
|
546
|
-
attributes :id, :title, :body
|
547
|
-
has_many :comments, :key => :comment_ids, :root => :comment_objects
|
290
|
+
url :post
|
548
291
|
end
|
549
292
|
```
|
550
293
|
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
{
|
555
|
-
"post": {
|
556
|
-
"id": 1,
|
557
|
-
"title": "New post",
|
558
|
-
"body": "A body!",
|
559
|
-
"comment_ids": [ 1 ]
|
560
|
-
},
|
561
|
-
"comment_objects": [
|
562
|
-
{ "id": 1, "body": "what a dumb post" }
|
563
|
-
]
|
564
|
-
}
|
565
|
-
```
|
566
|
-
|
567
|
-
You can also specify a different attribute to use rather than the ID of the
|
568
|
-
objects:
|
569
|
-
|
570
|
-
```ruby
|
571
|
-
class PostSerializer < ActiveModel::Serializer
|
572
|
-
embed :ids, :include => true
|
573
|
-
|
574
|
-
attributes :id, :title, :body
|
575
|
-
has_many :comments, :embed_key => :external_id
|
576
|
-
end
|
577
|
-
```
|
294
|
+
On this example every ```Post``` object will be cached with
|
295
|
+
the key ```"post/#{post.id}-#{post.updated_at}"```. You can use this key to expire it as you want,
|
296
|
+
but in this case it will be automatically expired after 3 hours.
|
578
297
|
|
579
|
-
|
580
|
-
|
581
|
-
```json
|
582
|
-
{
|
583
|
-
"post": {
|
584
|
-
"id": 1,
|
585
|
-
"title": "New post",
|
586
|
-
"body": "A body!",
|
587
|
-
"comment_ids": [ "COMM001" ]
|
588
|
-
},
|
589
|
-
"comments": [
|
590
|
-
{ "id": 1, "external_id": "COMM001", "body": "what a dumb post" }
|
591
|
-
]
|
592
|
-
}
|
593
|
-
```
|
298
|
+
### Fragmenting Caching
|
594
299
|
|
595
|
-
|
596
|
-
data in bulk and load it into a local store. For these clients, the ability to
|
597
|
-
easily see all of the data per type, rather than having to recursively scan the
|
598
|
-
data looking for information, is extremely useful.
|
300
|
+
If there is some API endpoint that shouldn't be fully cached, you can still optimise it, using Fragment Cache on the attributes and relationships that you want to cache.
|
599
301
|
|
600
|
-
|
601
|
-
Ajax requests, you probably just want to use the default embedded behavior.
|
302
|
+
You can define the attribute by using ```only``` or ```except``` option on cache method.
|
602
303
|
|
603
|
-
|
304
|
+
**[NOTE] Cache serializers will be used at their relationships**
|
604
305
|
|
605
|
-
|
606
|
-
provides to the serializer when you call `render :json`. By default, this is
|
607
|
-
`current_user`, but can be customized in your controller by calling
|
608
|
-
`serialization_scope`:
|
306
|
+
Example:
|
609
307
|
|
610
308
|
```ruby
|
611
|
-
class
|
612
|
-
|
613
|
-
|
614
|
-
```
|
615
|
-
|
616
|
-
The above example will also change the scope name from `current_user` to
|
617
|
-
`current_admin`.
|
618
|
-
|
619
|
-
Please note that, until now, `serialization_scope` doesn't accept a second
|
620
|
-
object with options for specifying which actions should or should not take a
|
621
|
-
given scope in consideration.
|
309
|
+
class PostSerializer < ActiveModel::Serializer
|
310
|
+
cache key: 'post', expires_in: 3.hours, only: [:title]
|
311
|
+
attributes :title, :body
|
622
312
|
|
623
|
-
|
313
|
+
has_many :comments
|
624
314
|
|
625
|
-
|
626
|
-
class SomeController < ApplicationController
|
627
|
-
serialization_scope :current_admin, :except => [:index, :show]
|
315
|
+
url :post
|
628
316
|
end
|
629
317
|
```
|
630
318
|
|
631
|
-
|
632
|
-
consideration for its scope, you may use something like this:
|
319
|
+
## Getting Help
|
633
320
|
|
634
|
-
|
635
|
-
class CitiesController < ApplicationController
|
636
|
-
serialization_scope nil
|
321
|
+
If you find a bug, please report an [Issue](https://github.com/rails-api/active_model_serializers/issues/new).
|
637
322
|
|
638
|
-
|
639
|
-
@cities = City.all
|
323
|
+
If you have a question, please [post to Stack Overflow](http://stackoverflow.com/questions/tagged/active-model-serializers).
|
640
324
|
|
641
|
-
|
642
|
-
end
|
325
|
+
Thanks!
|
643
326
|
|
644
|
-
|
645
|
-
@city = City.find(params[:id])
|
646
|
-
|
647
|
-
render :json => @city, :scope => current_admin, :scope_name => :current_admin
|
648
|
-
end
|
649
|
-
end
|
650
|
-
```
|
327
|
+
# Contributing
|
651
328
|
|
652
|
-
|
653
|
-
for the current user, the advantage of this approach is that, by setting
|
654
|
-
`serialization_scope` to `nil`, the `index` action no longer will need to make
|
655
|
-
that query, only the `show` action will.
|
329
|
+
See [CONTRIBUTING.md](https://github.com/rails-api/active_model_serializers/blob/master/CONTRIBUTING.md)
|