active_model_serializers 0.8.3 → 0.10.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.travis.yml +18 -20
  4. data/CHANGELOG.md +8 -67
  5. data/CONTRIBUTING.md +31 -0
  6. data/Gemfile +14 -1
  7. data/{MIT-LICENSE.txt → LICENSE.txt} +3 -2
  8. data/README.md +169 -495
  9. data/Rakefile +6 -12
  10. data/active_model_serializers.gemspec +21 -19
  11. data/lib/action_controller/serialization.rb +36 -27
  12. data/lib/active_model/serializer/adapter/flatten_json.rb +12 -0
  13. data/lib/active_model/serializer/adapter/fragment_cache.rb +78 -0
  14. data/lib/active_model/serializer/adapter/json/fragment_cache.rb +15 -0
  15. data/lib/active_model/serializer/adapter/json.rb +50 -0
  16. data/lib/active_model/serializer/adapter/json_api/fragment_cache.rb +23 -0
  17. data/lib/active_model/serializer/adapter/json_api.rb +156 -0
  18. data/lib/active_model/serializer/adapter/null.rb +11 -0
  19. data/lib/active_model/serializer/adapter.rb +96 -0
  20. data/lib/active_model/serializer/array_serializer.rb +35 -0
  21. data/lib/active_model/serializer/configuration.rb +13 -0
  22. data/lib/active_model/serializer/fieldset.rb +40 -0
  23. data/lib/active_model/serializer/railtie.rb +8 -0
  24. data/lib/active_model/{serializers → serializer}/version.rb +1 -1
  25. data/lib/active_model/serializer.rb +177 -440
  26. data/lib/active_model_serializers.rb +10 -86
  27. data/lib/generators/serializer/USAGE +0 -3
  28. data/lib/generators/serializer/resource_override.rb +12 -0
  29. data/lib/generators/serializer/serializer_generator.rb +1 -6
  30. data/lib/generators/serializer/templates/serializer.rb +2 -13
  31. data/test/action_controller/adapter_selector_test.rb +53 -0
  32. data/test/action_controller/explicit_serializer_test.rb +134 -0
  33. data/test/action_controller/json_api_linked_test.rb +179 -0
  34. data/test/action_controller/rescue_from_test.rb +32 -0
  35. data/test/{serialization_scope_name_test.rb → action_controller/serialization_scope_name_test.rb} +7 -11
  36. data/test/action_controller/serialization_test.rb +383 -0
  37. data/test/adapter/fragment_cache_test.rb +27 -0
  38. data/test/adapter/json/belongs_to_test.rb +48 -0
  39. data/test/adapter/json/collection_test.rb +73 -0
  40. data/test/adapter/json/has_many_test.rb +36 -0
  41. data/test/adapter/json_api/belongs_to_test.rb +157 -0
  42. data/test/adapter/json_api/collection_test.rb +96 -0
  43. data/test/adapter/json_api/has_many_embed_ids_test.rb +45 -0
  44. data/test/adapter/json_api/has_many_explicit_serializer_test.rb +98 -0
  45. data/test/adapter/json_api/has_many_test.rb +110 -0
  46. data/test/adapter/json_api/has_one_test.rb +61 -0
  47. data/test/adapter/json_api/linked_test.rb +283 -0
  48. data/test/adapter/json_test.rb +34 -0
  49. data/test/adapter/null_test.rb +25 -0
  50. data/test/adapter_test.rb +43 -0
  51. data/test/array_serializer_test.rb +31 -63
  52. data/test/fixtures/poro.rb +230 -0
  53. data/test/generators/scaffold_controller_generator_test.rb +24 -0
  54. data/test/{generators_test.rb → generators/serializer_generator_test.rb} +2 -36
  55. data/test/serializers/adapter_for_test.rb +50 -0
  56. data/test/serializers/associations_test.rb +127 -0
  57. data/test/serializers/attribute_test.rb +38 -0
  58. data/test/serializers/attributes_test.rb +63 -0
  59. data/test/serializers/cache_test.rb +138 -0
  60. data/test/serializers/configuration_test.rb +15 -0
  61. data/test/serializers/fieldset_test.rb +26 -0
  62. data/test/serializers/meta_test.rb +107 -0
  63. data/test/serializers/options_test.rb +21 -0
  64. data/test/serializers/serializer_for_test.rb +65 -0
  65. data/test/serializers/urls_test.rb +26 -0
  66. data/test/test_helper.rb +28 -16
  67. metadata +109 -43
  68. data/DESIGN.textile +0 -586
  69. data/Gemfile.edge +0 -9
  70. data/bench/perf.rb +0 -43
  71. data/cruft.md +0 -19
  72. data/lib/active_model/array_serializer.rb +0 -104
  73. data/lib/active_model/serializer/associations.rb +0 -233
  74. data/lib/active_record/serializer_override.rb +0 -16
  75. data/lib/generators/resource_override.rb +0 -13
  76. data/test/association_test.rb +0 -592
  77. data/test/caching_test.rb +0 -96
  78. data/test/no_serialization_scope_test.rb +0 -34
  79. data/test/serialization_test.rb +0 -392
  80. data/test/serializer_support_test.rb +0 -51
  81. data/test/serializer_test.rb +0 -1465
  82. data/test/test_fakes.rb +0 -217
data/README.md CHANGED
@@ -1,655 +1,329 @@
1
- [![Build Status](https://api.travis-ci.org/rails-api/active_model_serializers.png)](https://travis-ci.org/rails-api/active_model_serializers) [![Code Climate](https://codeclimate.com/github/rails-api/active_model_serializers.png)](https://codeclimate.com/github/rails-api/active_model_serializers)
1
+ # ActiveModel::Serializers
2
2
 
3
- # Purpose
3
+ [![Build Status](https://travis-ci.org/rails-api/active_model_serializers.svg)](https://travis-ci.org/rails-api/active_model_serializers)
4
4
 
5
- The purpose of `ActiveModel::Serializers` is to provide an object to
6
- encapsulate serialization of `ActiveModel` objects, including `ActiveRecord`
7
- objects.
5
+ ActiveModel::Serializers brings convention over configuration to your JSON generation.
8
6
 
9
- Serializers know about both a model and the `current_user`, so you can
10
- customize serialization based upon whether a user is authorized to see the
11
- content.
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
- In short, **serializers replace hash-driven development with object-oriented
14
- development.**
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
- # Installing Serializers
14
+ # RELEASE CANDIDATE, PLEASE READ
17
15
 
18
- The easiest way to install `ActiveModel::Serializers` is to add it to your
19
- `Gemfile`:
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
- ```ruby
22
- gem "active_model_serializers", "~> 0.8.0"
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
- # Creating a Serializer
23
+ ## Example
32
24
 
33
- The easiest way to create a new serializer is to generate a new resource, which
34
- will generate a serializer at the same time:
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
- $ rails g resource post title:string body:string
38
- ```
29
+ ```ruby
30
+ class PostSerializer < ActiveModel::Serializer
31
+ cache key: 'posts', expires_in: 3.hours
32
+ attributes :title, :body
39
33
 
40
- This will generate a serializer in `app/serializers/post_serializer.rb` for
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
- All new serializers descend from ActiveModel::Serializer
40
+ and
63
41
 
64
- # render :json
42
+ ```ruby
43
+ class CommentSerializer < ActiveModel::Serializer
44
+ attributes :name, :body
65
45
 
66
- In your controllers, when you use `render :json`, Rails will now first search
67
- for a serializer for the object and use it if available.
46
+ belongs_to :post
68
47
 
69
- ```ruby
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
- In this case, Rails will look for a serializer named `PostSerializer`, and if
79
- it exists, use it to serialize the `Post`.
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
- class Post < ActiveRecord::Base
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
- #### 2. Specify the serializer when you render the object:
60
+ or
98
61
 
99
62
  ```ruby
100
- render :json => @post, :serializer => FancyPostSerializer
63
+ ActiveModel::Serializer.config.adapter = :json_api
101
64
  ```
102
65
 
103
- ## Arrays
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
- In your controllers, when you use `render :json` for an array of objects, AMS will
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 :title, :body
112
- end
73
+ attributes :id, :body
113
74
 
114
- class PostsController < ApplicationController
115
- def index
116
- @posts = Post.all
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
- Given the example above, the index action will return
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
- render :json => @posts, :root => "some_posts"
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
- ```ruby
155
- render :json => @posts, :each_serializer => FancyPostSerializer
89
+ render json: @post
90
+ end
91
+ end
156
92
  ```
157
93
 
158
- ## Disabling the root element
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
- In an initializer:
97
+ ### Specify a serializer
165
98
 
166
- ```ruby
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
- #### 2. Disable root per render call in your controller
101
+ #### 1. For a resource:
177
102
 
178
103
  ```ruby
179
- render :json => @posts, :root => false
104
+ render json: @post, serializer: PostPreviewSerializer
180
105
  ```
181
106
 
182
- #### 3. Subclass the serializer, and specify using it
107
+ #### 2. For an array resource:
183
108
 
184
109
  ```ruby
185
- class CustomArraySerializer < ActiveModel::ArraySerializer
186
- self.root = false
187
- end
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
- # controller:
190
- render :json => @posts, :serializer => CustomArraySerializer
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
- #### 4. Define default_serializer_options in your controller
118
+ ### Meta
194
119
 
195
- If you define `default_serializer_options` method in your controller,
196
- all serializers in actions of this controller and it's children will use them.
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
- def default_serializer_options
201
- {
202
- root: false
203
- }
204
- end
124
+ render json: @post, meta: { total: 10 }
205
125
  ```
206
126
 
207
- ## Getting the old version
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
- class PostSerializer < ActiveModel::Serializer
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
- ## Attributes
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
- For specified attributes, a serializer will look up the attribute on the
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
- Before looking up the attribute on the object, a serializer will check for the
232
- presence of a method with the name of the attribute. This allows serializers to
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
- class PersonSerializer < ActiveModel::Serializer
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
- Within a serializer's methods, you can access the object being
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
- Serializers will check for the presence of a method named
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, :title, :body, :author
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
- ```ruby
273
- class PersonSerializer < ActiveModel::Serializer
274
- attributes :first_name, :last_name, {:full_name => :string}
153
+ has_many :comments
275
154
 
276
- def full_name
277
- "#{object.first_name} #{object.last_name}"
155
+ def comments
156
+ object.comments.active
278
157
  end
279
158
  end
280
159
  ```
281
160
 
282
- If you would like the key in the outputted JSON to be different from its name
283
- in ActiveRecord, you can use the `:key` option to customize it:
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
- ```ruby
299
- render :json => @posts, :serializer => CustomArraySerializer, :meta => {:total => 10}
171
+ def body
172
+ object.body.downcase
173
+ end
174
+ end
300
175
  ```
301
176
 
302
- The above usage of `:meta` will produce the following:
177
+ ### Built in Adapters
303
178
 
304
- ```json
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
- If you would like to change the meta key name you can use the `:meta_key` option:
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 :json => @posts, :serializer => CustomArraySerializer, :meta => {:total => 10}, :meta_key => 'meta_object'
187
+ render @posts, include: ['authors', 'comments']
188
+ # or
189
+ render @posts, include: 'authors,comments'
318
190
  ```
319
191
 
320
- The above usage of `:meta_key` will produce the following:
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
- If you would like direct, low-level control of attribute serialization, you can
333
- completely override the `attributes` method to return the hash you need:
194
+ Add this line to your application's Gemfile:
334
195
 
335
- ```ruby
336
- class PersonSerializer < ActiveModel::Serializer
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
- ## Associations
200
+ And then execute:
351
201
 
352
- For specified associations, the serializer will look up the association and
353
- then serialize each element of the association. For instance, a `has_many
354
- :comments` association will create a new `CommentSerializer` for each comment
355
- and use it to serialize the comment.
202
+ ```
203
+ $ bundle
204
+ ```
356
205
 
357
- By default, serializers simply look up the association on the original object.
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
- ```ruby
363
- class PostSerializer < ActiveModel::Serializer
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
- # only let the user see comments he created.
368
- def comments
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
- As with attributes, you can change the JSON key that the serializer should
375
- use for a particular association.
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
- # look up comments, but use +my_comments+ as the key in JSON
382
- has_many :comments, :key => :my_comments
383
- end
219
+ ```
220
+ $ rails g serializer post
384
221
  ```
385
222
 
386
- Also, as with attributes, serializers will check for the presence
387
- of a method named `include_[ASSOCIATION]?` to determine whether a particular association
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 :id, :title, :body
228
+ attributes :title, :body
229
+
393
230
  has_many :comments
231
+ has_one :author
394
232
 
395
- def include_comments?
396
- !object.comments_disabled?
397
- end
233
+ url :post
398
234
  end
399
235
  ```
400
236
 
401
- If you would like lower-level control of association serialization, you can
402
- override `include_associations!` to specify which associations should be included:
237
+ and
403
238
 
404
239
  ```ruby
405
- class PostSerializer < ActiveModel::Serializer
406
- attributes :id, :title, :body
407
- has_one :author
408
- has_many :comments
240
+ class CommentSerializer < ActiveModel::Serializer
241
+ attributes :name, :body
409
242
 
410
- def include_associations!
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
- ```ruby
420
- has_many :comments, :serializer => CommentShortSerializer
421
- has_one :reviewer, :polymorphic => true
245
+ url [:post, :comment]
246
+ end
422
247
  ```
423
248
 
424
- Serializers are only concerned with multiplicity, and not ownership. `belongs_to` ActiveRecord associations can be included using `has_one` in your serializer.
249
+ The attribute names are a **whitelist** of attributes to be serialized.
425
250
 
426
- ## Embedding Associations
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
- By default, associations will be embedded inside the serialized object. So if
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
- ```json
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
- This is convenient for simple use-cases, but for more complex clients, it is
445
- better to supply an Array of IDs for the association. This makes your API more
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
- To embed IDs instead of associations, simply use the `embed` class method:
264
+ ## Caching
449
265
 
450
- ```ruby
451
- class PostSerializer < ActiveModel::Serializer
452
- embed :ids
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
- attributes :id, :title, :body
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
- Now, any associations will be supplied as an Array of IDs:
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
- Alternatively, you can choose to embed only the ids or the associated objects per association:
275
+ **[NOTE] The cache is automatically expired after update an object but it's not deleted.**
473
276
 
474
277
  ```ruby
475
- class PostSerializer < ActiveModel::Serializer
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
- In addition to supplying an Array of IDs, you may want to side-load the data
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
- embed :ids, :include => true
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
- You can also specify a different root for the embedded objects than the key
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
- This would generate JSON that would look like this:
552
-
553
- ```json
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
- This would generate JSON that would look like this:
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
- **NOTE**: The `embed :ids` mechanism is primary useful for clients that process
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
- If you are mostly working with the data in simple scenarios and manually making
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
- ## Customizing Scope
304
+ **[NOTE] Cache serializers will be used at their relationships**
604
305
 
605
- In a serializer, `current_user` is the current authorization scope which the controller
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 ApplicationController < ActionController::Base
612
- serialization_scope :current_admin
613
- end
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
- To be clear, it's not possible, yet, to do something like this:
313
+ has_many :comments
624
314
 
625
- ```ruby
626
- class SomeController < ApplicationController
627
- serialization_scope :current_admin, :except => [:index, :show]
315
+ url :post
628
316
  end
629
317
  ```
630
318
 
631
- So, in order to have a fine grained control of what each action should take in
632
- consideration for its scope, you may use something like this:
319
+ ## Getting Help
633
320
 
634
- ```ruby
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
- def index
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
- render :json => @cities, :each_serializer => CitySerializer
642
- end
325
+ Thanks!
643
326
 
644
- def show
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
- Assuming that the `current_admin` method needs to make a query in the database
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)