active_model_serializers 0.8.3 → 0.9.0.alpha1

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.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -5
  3. data/CONTRIBUTING.md +20 -0
  4. data/DESIGN.textile +4 -4
  5. data/{MIT-LICENSE.txt → MIT-LICENSE} +0 -0
  6. data/README.md +187 -96
  7. data/lib/action_controller/serialization.rb +30 -16
  8. data/lib/active_model/array_serializer.rb +36 -82
  9. data/lib/active_model/default_serializer.rb +22 -0
  10. data/lib/active_model/serializable.rb +25 -0
  11. data/lib/active_model/serializer/associations.rb +53 -211
  12. data/lib/active_model/serializer/config.rb +31 -0
  13. data/lib/active_model/serializer/generators/resource_override.rb +13 -0
  14. data/lib/{generators → active_model/serializer/generators}/serializer/USAGE +0 -0
  15. data/lib/active_model/serializer/generators/serializer/scaffold_controller_generator.rb +14 -0
  16. data/lib/active_model/serializer/generators/serializer/serializer_generator.rb +37 -0
  17. data/lib/active_model/serializer/generators/serializer/templates/controller.rb +93 -0
  18. data/lib/active_model/serializer/generators/serializer/templates/serializer.rb +8 -0
  19. data/lib/active_model/serializer/railtie.rb +10 -0
  20. data/lib/active_model/{serializers → serializer}/version.rb +1 -1
  21. data/lib/active_model/serializer.rb +126 -448
  22. data/lib/active_model/serializer_support.rb +5 -0
  23. data/lib/active_model_serializers.rb +7 -86
  24. data/test/coverage_setup.rb +15 -0
  25. data/test/fixtures/active_record.rb +92 -0
  26. data/test/fixtures/poro.rb +64 -0
  27. data/test/integration/action_controller/serialization_test.rb +234 -0
  28. data/test/integration/active_record/active_record_test.rb +77 -0
  29. data/test/integration/generators/resource_generator_test.rb +26 -0
  30. data/test/integration/generators/scaffold_controller_generator_test.rb +67 -0
  31. data/test/integration/generators/serializer_generator_test.rb +41 -0
  32. data/test/test_app.rb +11 -0
  33. data/test/test_helper.rb +8 -19
  34. data/test/tmp/app/serializers/account_serializer.rb +3 -0
  35. data/test/unit/active_model/array_serializer/meta_test.rb +53 -0
  36. data/test/unit/active_model/array_serializer/root_test.rb +102 -0
  37. data/test/unit/active_model/array_serializer/scope_test.rb +24 -0
  38. data/test/unit/active_model/array_serializer/serialization_test.rb +83 -0
  39. data/test/unit/active_model/default_serializer_test.rb +13 -0
  40. data/test/unit/active_model/serializer/associations/build_serializer_test.rb +21 -0
  41. data/test/unit/active_model/serializer/associations_test.rb +19 -0
  42. data/test/unit/active_model/serializer/attributes_test.rb +41 -0
  43. data/test/unit/active_model/serializer/config_test.rb +86 -0
  44. data/test/unit/active_model/serializer/filter_test.rb +49 -0
  45. data/test/unit/active_model/serializer/has_many_test.rb +173 -0
  46. data/test/unit/active_model/serializer/has_one_test.rb +151 -0
  47. data/test/unit/active_model/serializer/meta_test.rb +39 -0
  48. data/test/unit/active_model/serializer/root_test.rb +117 -0
  49. data/test/unit/active_model/serializer/scope_test.rb +49 -0
  50. metadata +80 -65
  51. data/.gitignore +0 -18
  52. data/.travis.yml +0 -28
  53. data/Gemfile +0 -4
  54. data/Gemfile.edge +0 -9
  55. data/Rakefile +0 -18
  56. data/active_model_serializers.gemspec +0 -24
  57. data/bench/perf.rb +0 -43
  58. data/cruft.md +0 -19
  59. data/lib/active_record/serializer_override.rb +0 -16
  60. data/lib/generators/resource_override.rb +0 -13
  61. data/lib/generators/serializer/serializer_generator.rb +0 -42
  62. data/lib/generators/serializer/templates/serializer.rb +0 -19
  63. data/test/array_serializer_test.rb +0 -75
  64. data/test/association_test.rb +0 -592
  65. data/test/caching_test.rb +0 -96
  66. data/test/generators_test.rb +0 -85
  67. data/test/no_serialization_scope_test.rb +0 -34
  68. data/test/serialization_scope_name_test.rb +0 -67
  69. data/test/serialization_test.rb +0 -392
  70. data/test/serializer_support_test.rb +0 -51
  71. data/test/serializer_test.rb +0 -1465
  72. data/test/test_fakes.rb +0 -217
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 94274a9d3a573ae8f656719aef33825cabb68673
4
- data.tar.gz: b1d614a90149ec109b67e963464c232d0b5ed3f1
3
+ metadata.gz: aeb402f8407aece224529052410e2ad33485d7eb
4
+ data.tar.gz: db4621bc2e62921b75a8e02e77b30e4782951b1a
5
5
  SHA512:
6
- metadata.gz: cc3140d1676014d8ce4aa0add253d247c55652a689cb83e7f7f7a71a81ae8d7c601fc5e2d261d415e243857a479a15156d0a84a67beb1c72475ef51c063cdfca
7
- data.tar.gz: cfc92ac9bb7dfca07cebdd32ef4a120aa5784cc7f1a6bfc8a65900b553be736b174b6bbf22fb7ebd55e8295ea1d118373245396e3c0ac883e954ab27e925bca2
6
+ metadata.gz: 5496e9420a975333a78f239eb2bbeb680f4240ec22e1bdbbe989fceb480325e14fbd96ab706510f0b0297b8317d85298451b034eabb5f1e67627e03bd0aa5c57
7
+ data.tar.gz: 2320ddcf2bf5c13028669dabc470331008de7e3fe79bf3f4ffb4d70df701731061541ccfc4ed57160dc520b8637e02e75b8510bfb6c72470be4ffd2603618be1
data/CHANGELOG.md CHANGED
@@ -1,4 +1,24 @@
1
- # UNRELEASED
1
+ # VERSION 0.9.0.pre
2
+
3
+ * The following methods were removed
4
+ - Model#active\_model\_serializer
5
+ - Serializer#include!
6
+ - Serializer#include?
7
+ - Serializer#attr\_disabled=
8
+ - Serializer#cache
9
+ - Serializer#perform\_caching
10
+ - Serializer#schema (needs more discussion)
11
+ - Serializer#attribute
12
+ - Serializer#include\_#{name}? (filter method added)
13
+ - Serializer#attributes (took a hash)
14
+
15
+ * The following things were added
16
+ - Serializer#filter method
17
+ - CONFIG object
18
+
19
+ * Remove support for ruby 1.8 versions.
20
+
21
+ * Require rails >= 3.2.
2
22
 
3
23
  # VERSION 0.8.1
4
24
 
@@ -10,13 +30,13 @@
10
30
 
11
31
  * A new DefaultSerializer ensures that POROs behave the same way as ActiveModels.
12
32
 
13
- * If you wish to override ActiveRecord::Base#to_Json, you can now require
14
- 'active_record/serializer_override'. We don't recommend you do this, but
33
+ * If you wish to override ActiveRecord::Base#to\_Json, you can now require
34
+ 'active\_record/serializer\_override'. We don't recommend you do this, but
15
35
  many users do, so we've left it optional.
16
36
 
17
37
  * Fixed a bug where ActionController wouldn't always have MimeResponds.
18
38
 
19
- * An optinal caching feature allows you to cache JSON & hashes that AMS uses.
39
+ * An optional caching feature allows you to cache JSON & hashes that AMS uses.
20
40
  Adding 'cached true' to your Serializers will turn on this cache.
21
41
 
22
42
  * URL helpers used inside of Engines now work properly.
@@ -61,7 +81,7 @@
61
81
  * Allow serialization_scope to be disabled with serialization_scope nil
62
82
  * Array serializer should support pure ruby objects besides serializers
63
83
 
64
- # VERSION 0.5.0 (May 16, 2012)
84
+ # VERSION 0.5.0
65
85
 
66
86
  * First tagged version
67
87
  * Changes generators to always generate an ApplicationSerializer
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,20 @@
1
+ Contributing to AMS
2
+ ===================
3
+
4
+ First of all, **thank you**!
5
+
6
+ Now, for the details:
7
+
8
+ Please file issues on the [GitHub Issues
9
+ list](https://github.com/rails-api/active_model_serializers/issues).
10
+
11
+ Please discuss new features or ask for feedback about a new feature [on
12
+ rails-api-core](https://groups.google.com/forum/#!forum/rails-api-core).
13
+
14
+ If you want a feature implemented, the best way to get it done is to submit a
15
+ pull request that implements it. Tests and docs would be nice.
16
+
17
+ Please include a CHANGELOG with all entries that change behavior.
18
+
19
+ :heart: :sparkling_heart: :heart:
20
+
data/DESIGN.textile CHANGED
@@ -358,8 +358,8 @@ Here is an example:
358
358
 
359
359
  <pre lang="ruby">
360
360
  class UserSerializer < ActiveModel::Serializer
361
- has_many :followed_posts, :key => :posts
362
- has_one :owned_account, :key => :account
361
+ has_many :followed_posts, key: :posts
362
+ has_one :owned_account, key: :account
363
363
  end
364
364
  </pre>
365
365
 
@@ -370,8 +370,8 @@ to set it explicitly:
370
370
 
371
371
  <pre lang="ruby">
372
372
  class UserSerializer < ActiveModel::Serializer
373
- has_many :followed_posts, :key => :posts, :serializer => CustomPostSerializer
374
- has_one :owne_account, :key => :account, :serializer => PrivateAccountSerializer
373
+ has_many :followed_posts, key: :posts, serializer: CustomPostSerializer
374
+ has_one :owne_account, key: :account, serializer: PrivateAccountSerializer
375
375
  end
376
376
  </pre>
377
377
 
File without changes
data/README.md CHANGED
@@ -1,10 +1,20 @@
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
+ [![Build Status](https://api.travis-ci.org/rails-api/active_model_serializers.png)](https://travis-ci.org/rails-api/active_model_serializers)
2
+ [![Code Climate](https://codeclimate.com/github/rails-api/active_model_serializers.png)](https://codeclimate.com/github/rails-api/active_model_serializers)
3
+ [![Coverage Status](https://coveralls.io/repos/rails-api/active_model_serializers/badge.png?branch=master)](https://coveralls.io/r/rails-api/active_model_serializers)
2
4
 
3
- # Purpose
5
+ # ActiveModel::Serializers
4
6
 
5
- The purpose of `ActiveModel::Serializers` is to provide an object to
6
- encapsulate serialization of `ActiveModel` objects, including `ActiveRecord`
7
- objects.
7
+ ## Master - 0.9.0
8
+
9
+ **master is under development, there are some incompatible changes with the current stable release.**
10
+
11
+ If you want to read the stable documentation visit [0.8 README](https://github.com/rails-api/active_model_serializers/blob/0-8-stable/README.md)
12
+
13
+ ## Purpose
14
+
15
+ `ActiveModel::Serializers` encapsulates the JSON serialization of objects.
16
+ Objects that respond to read\_attribute\_for\_serialization
17
+ (including `ActiveModel` and `ActiveRecord` objects) are supported.
8
18
 
9
19
  Serializers know about both a model and the `current_user`, so you can
10
20
  customize serialization based upon whether a user is authorized to see the
@@ -13,13 +23,13 @@ content.
13
23
  In short, **serializers replace hash-driven development with object-oriented
14
24
  development.**
15
25
 
16
- # Installing Serializers
26
+ # Installing
17
27
 
18
28
  The easiest way to install `ActiveModel::Serializers` is to add it to your
19
29
  `Gemfile`:
20
30
 
21
31
  ```ruby
22
- gem "active_model_serializers", "~> 0.8.0"
32
+ gem "active_model_serializers"
23
33
  ```
24
34
 
25
35
  Then, install it on the command line:
@@ -28,6 +38,16 @@ Then, install it on the command line:
28
38
  $ bundle install
29
39
  ```
30
40
 
41
+ #### Ruby 1.8 is no longer supported!
42
+
43
+ If you must use a ruby 1.8 version (MRI 1.8.7, REE, Rubinius 1.8, or JRuby 1.8), you need to use version 0.8.x.
44
+ Versions after 0.9.0 do not support ruby 1.8. To specify version 0.8, include this in your Gemfile:
45
+
46
+ ```ruby
47
+ gem "active_model_serializers", "~> 0.8.0"
48
+ ```
49
+
50
+
31
51
  # Creating a Serializer
32
52
 
33
53
  The easiest way to create a new serializer is to generate a new resource, which
@@ -45,17 +65,11 @@ the serializer generator:
45
65
  $ rails g serializer post
46
66
  ```
47
67
 
48
- ### Support for PORO's and other ORM's.
68
+ ### Support for POROs
49
69
 
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.
70
+ Currently `ActiveModel::Serializers` expects objects to implement
71
+ read\_attribute\_for\_serialization. That's all you need to do to have
72
+ your POROs supported.
59
73
 
60
74
  # ActiveModel::Serializer
61
75
 
@@ -70,7 +84,7 @@ for a serializer for the object and use it if available.
70
84
  class PostsController < ApplicationController
71
85
  def show
72
86
  @post = Post.find(params[:id])
73
- render :json => @post
87
+ render json: @post
74
88
  end
75
89
  end
76
90
  ```
@@ -82,22 +96,11 @@ This also works with `respond_with`, which uses `to_json` under the hood. Also
82
96
  note that any options passed to `render :json` will be passed to your
83
97
  serializer and available as `@options` inside.
84
98
 
85
- To specify a custom serializer for an object, there are 2 options:
86
-
87
- #### 1. Specify the serializer in your model:
88
-
89
- ```ruby
90
- class Post < ActiveRecord::Base
91
- def active_model_serializer
92
- FancyPostSerializer
93
- end
94
- end
95
- ```
96
-
97
- #### 2. Specify the serializer when you render the object:
99
+ To specify a custom serializer for an object, you can specify the
100
+ serializer when you render the object:
98
101
 
99
102
  ```ruby
100
- render :json => @post, :serializer => FancyPostSerializer
103
+ render json: @post, serializer: FancyPostSerializer
101
104
  ```
102
105
 
103
106
  ## Arrays
@@ -114,7 +117,7 @@ end
114
117
  class PostsController < ApplicationController
115
118
  def index
116
119
  @posts = Post.all
117
- render :json => @posts
120
+ render json: @posts
118
121
  end
119
122
  end
120
123
  ```
@@ -135,7 +138,7 @@ By default, the root element is the name of the controller. For example, `PostsC
135
138
  generates a root element "posts". To change it:
136
139
 
137
140
  ```ruby
138
- render :json => @posts, :root => "some_posts"
141
+ render json: @posts, root: "some_posts"
139
142
  ```
140
143
 
141
144
  You may disable the root element for arrays at the top level, which will result in
@@ -152,7 +155,7 @@ root element of the array with any of those methods will produce
152
155
  To specify a custom serializer for the items within an array:
153
156
 
154
157
  ```ruby
155
- render :json => @posts, :each_serializer => FancyPostSerializer
158
+ render json: @posts, each_serializer: FancyPostSerializer
156
159
  ```
157
160
 
158
161
  ## Disabling the root element
@@ -164,19 +167,17 @@ You have 4 options to disable the root element, each with a slightly different s
164
167
  In an initializer:
165
168
 
166
169
  ```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
170
+ # Disable for all serializers (except ArraySerializer)
171
+ ActiveModel::Serializer.root = false
172
+
173
+ # Disable for ArraySerializer
174
+ ActiveModel::ArraySerializer.root = false
174
175
  ```
175
176
 
176
177
  #### 2. Disable root per render call in your controller
177
178
 
178
179
  ```ruby
179
- render :json => @posts, :root => false
180
+ render json: @posts, root: false
180
181
  ```
181
182
 
182
183
  #### 3. Subclass the serializer, and specify using it
@@ -187,7 +188,7 @@ class CustomArraySerializer < ActiveModel::ArraySerializer
187
188
  end
188
189
 
189
190
  # controller:
190
- render :json => @posts, :serializer => CustomArraySerializer
191
+ render json: @posts, serializer: CustomArraySerializer
191
192
  ```
192
193
 
193
194
  #### 4. Define default_serializer_options in your controller
@@ -207,7 +208,7 @@ end
207
208
  ## Getting the old version
208
209
 
209
210
  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
+ change `render :json` to `render json: @your_object.to_json`.
211
212
 
212
213
  # Attributes and Associations
213
214
 
@@ -245,49 +246,57 @@ end
245
246
  Within a serializer's methods, you can access the object being
246
247
  serialized as `object`.
247
248
 
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).
252
-
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:
249
+ Since this shadows any attribute named `object`, you can include them through `object.object`. For example:
257
250
 
258
251
  ```ruby
259
- class PostSerializer < ActiveModel::Serializer
260
- attributes :id, :title, :body, :author
252
+ class VersionSerializer < ActiveModel::Serializer
253
+ attribute :version_object, key: :object
261
254
 
262
- def include_author?
263
- current_user.admin?
255
+ def version_object
256
+ object.object
264
257
  end
265
258
  end
266
259
  ```
267
260
 
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:
261
+ You can also access the `scope` method, which provides an
262
+ authorization context to your serializer. By default, the context
263
+ is the current user of your application, but this
264
+ [can be customized](#customizing-scope).
265
+
266
+ Serializers provides a method named `filter`, which should return an array
267
+ used to determine what attributes and associations should be included in the output.
268
+ This is typically used to customize output based on `current_user`. For example:
271
269
 
272
270
  ```ruby
273
- class PersonSerializer < ActiveModel::Serializer
274
- attributes :first_name, :last_name, {:full_name => :string}
271
+ class PostSerializer < ActiveModel::Serializer
272
+ attributes :id, :title, :body, :author
275
273
 
276
- def full_name
277
- "#{object.first_name} #{object.last_name}"
274
+ def filter(keys)
275
+ if scope.admin?
276
+ keys
277
+ else
278
+ keys - [:author]
279
+ end
278
280
  end
279
281
  end
280
282
  ```
281
283
 
284
+ And it's also safe to mutate keys argument by doing keys.delete(:author)
285
+ in case you want to avoid creating two extra arrays. Note that if you do an
286
+ in-place modification, you still need to return the modified array.
287
+
282
288
  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:
289
+ in ActiveRecord, you can declare the attribute with the different name
290
+ and redefine that method:
284
291
 
285
292
  ```ruby
286
293
  class PostSerializer < ActiveModel::Serializer
287
- attributes :id, :body
294
+ # look up subject on the model, but use title in the JSON
295
+ def title
296
+ object.subject
297
+ end
288
298
 
289
- # look up :subject on the model, but use +title+ in the JSON
290
- attribute :subject, :key => :title
299
+ attributes :id, :body, :title
291
300
  has_many :comments
292
301
  end
293
302
  ```
@@ -296,7 +305,7 @@ If you would like to add meta information to the outputted JSON, use the `:meta`
296
305
  option:
297
306
 
298
307
  ```ruby
299
- render :json => @posts, :serializer => CustomArraySerializer, :meta => {:total => 10}
308
+ render json: @posts, serializer: CustomArraySerializer, meta: {total: 10}
300
309
  ```
301
310
 
302
311
  The above usage of `:meta` will produce the following:
@@ -314,7 +323,7 @@ The above usage of `:meta` will produce the following:
314
323
  If you would like to change the meta key name you can use the `:meta_key` option:
315
324
 
316
325
  ```ruby
317
- render :json => @posts, :serializer => CustomArraySerializer, :meta => {:total => 10}, :meta_key => 'meta_object'
326
+ render json: @posts, serializer: CustomArraySerializer, meta: {total: 10}, meta_key: 'meta_object'
318
327
  ```
319
328
 
320
329
  The above usage of `:meta_key` will produce the following:
@@ -329,6 +338,9 @@ The above usage of `:meta_key` will produce the following:
329
338
  }
330
339
  ```
331
340
 
341
+ When using meta information, your serializer cannot have the `{ root: false }` option, as this would lead to
342
+ invalid JSON. If you do not have a root key, the meta information will be ignored.
343
+
332
344
  If you would like direct, low-level control of attribute serialization, you can
333
345
  completely override the `attributes` method to return the hash you need:
334
346
 
@@ -338,7 +350,7 @@ class PersonSerializer < ActiveModel::Serializer
338
350
 
339
351
  def attributes
340
352
  hash = super
341
- if current_user.admin?
353
+ if scope.admin?
342
354
  hash["ssn"] = object.ssn
343
355
  hash["secret"] = object.mothers_maiden_name
344
356
  end
@@ -357,7 +369,7 @@ and use it to serialize the comment.
357
369
  By default, serializers simply look up the association on the original object.
358
370
  You can customize this behavior by implementing a method with the name of the
359
371
  association and returning a different Array. Often, you will do this to
360
- customize the objects returned based on the current user.
372
+ customize the objects returned based on the current user (scope).
361
373
 
362
374
  ```ruby
363
375
  class PostSerializer < ActiveModel::Serializer
@@ -366,7 +378,7 @@ class PostSerializer < ActiveModel::Serializer
366
378
 
367
379
  # only let the user see comments he created.
368
380
  def comments
369
- object.comments.where(:created_by => current_user)
381
+ object.comments.where(created_by: scope)
370
382
  end
371
383
  end
372
384
  ```
@@ -379,27 +391,27 @@ class PostSerializer < ActiveModel::Serializer
379
391
  attributes :id, :title, :body
380
392
 
381
393
  # look up comments, but use +my_comments+ as the key in JSON
382
- has_many :comments, :key => :my_comments
394
+ has_many :comments, root: :my_comments
383
395
  end
384
396
  ```
385
397
 
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:
398
+ Also, as with attributes, serializers will execute a filter method to
399
+ determine which associations should be included in the output. For
400
+ example:
389
401
 
390
402
  ```ruby
391
403
  class PostSerializer < ActiveModel::Serializer
392
404
  attributes :id, :title, :body
393
405
  has_many :comments
394
406
 
395
- def include_comments?
396
- !object.comments_disabled?
407
+ def filter(keys)
408
+ keys.delete :comments if object.comments_disabled?
409
+ keys
397
410
  end
398
411
  end
399
412
  ```
400
413
 
401
- If you would like lower-level control of association serialization, you can
402
- override `include_associations!` to specify which associations should be included:
414
+ Or ...
403
415
 
404
416
  ```ruby
405
417
  class PostSerializer < ActiveModel::Serializer
@@ -407,9 +419,10 @@ class PostSerializer < ActiveModel::Serializer
407
419
  has_one :author
408
420
  has_many :comments
409
421
 
410
- def include_associations!
411
- include! :author if current_user.admin?
412
- include! :comments unless object.comments_disabled?
422
+ def filter(keys)
423
+ keys.delete :author unless scope.admin?
424
+ keys.delete :comments if object.comments_disabled?
425
+ keys
413
426
  end
414
427
  end
415
428
  ```
@@ -417,12 +430,15 @@ end
417
430
  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.:
418
431
 
419
432
  ```ruby
420
- has_many :comments, :serializer => CommentShortSerializer
421
- has_one :reviewer, :polymorphic => true
433
+ has_many :comments, serializer: CommentShortSerializer
434
+ has_one :reviewer, polymorphic: true
422
435
  ```
423
436
 
424
437
  Serializers are only concerned with multiplicity, and not ownership. `belongs_to` ActiveRecord associations can be included using `has_one` in your serializer.
425
438
 
439
+ NOTE: polymorphic was removed because was only supported for has\_one
440
+ associations and is in the TODO list of the project.
441
+
426
442
  ## Embedding Associations
427
443
 
428
444
  By default, associations will be embedded inside the serialized object. So if
@@ -506,7 +522,7 @@ You can specify that the data be included like this:
506
522
 
507
523
  ```ruby
508
524
  class PostSerializer < ActiveModel::Serializer
509
- embed :ids, :include => true
525
+ embed :ids, include: true
510
526
 
511
527
  attributes :id, :title, :body
512
528
  has_many :comments
@@ -536,15 +552,19 @@ this:
536
552
  }
537
553
  ```
538
554
 
555
+ When side-loading data, your serializer cannot have the `{ root: false }` option,
556
+ as this would lead to invalid JSON. If you do not have a root key, the `include`
557
+ instruction will be ignored
558
+
539
559
  You can also specify a different root for the embedded objects than the key
540
560
  used to reference them:
541
561
 
542
562
  ```ruby
543
563
  class PostSerializer < ActiveModel::Serializer
544
- embed :ids, :include => true
564
+ embed :ids, include: true
545
565
 
546
566
  attributes :id, :title, :body
547
- has_many :comments, :key => :comment_ids, :root => :comment_objects
567
+ has_many :comments, key: :comment_ids, root: :comment_objects
548
568
  end
549
569
  ```
550
570
 
@@ -569,10 +589,10 @@ objects:
569
589
 
570
590
  ```ruby
571
591
  class PostSerializer < ActiveModel::Serializer
572
- embed :ids, :include => true
592
+ embed :ids, include: true
573
593
 
574
594
  attributes :id, :title, :body
575
- has_many :comments, :embed_key => :external_id
595
+ has_many :comments, embed_key: :external_id
576
596
  end
577
597
  ```
578
598
 
@@ -613,7 +633,7 @@ class ApplicationController < ActionController::Base
613
633
  end
614
634
  ```
615
635
 
616
- The above example will also change the scope name from `current_user` to
636
+ The above example will also change the scope from `current_user` to
617
637
  `current_admin`.
618
638
 
619
639
  Please note that, until now, `serialization_scope` doesn't accept a second
@@ -624,7 +644,7 @@ To be clear, it's not possible, yet, to do something like this:
624
644
 
625
645
  ```ruby
626
646
  class SomeController < ApplicationController
627
- serialization_scope :current_admin, :except => [:index, :show]
647
+ serialization_scope :current_admin, except: [:index, :show]
628
648
  end
629
649
  ```
630
650
 
@@ -638,13 +658,13 @@ class CitiesController < ApplicationController
638
658
  def index
639
659
  @cities = City.all
640
660
 
641
- render :json => @cities, :each_serializer => CitySerializer
661
+ render json: @cities, each_serializer: CitySerializer
642
662
  end
643
663
 
644
664
  def show
645
665
  @city = City.find(params[:id])
646
666
 
647
- render :json => @city, :scope => current_admin, :scope_name => :current_admin
667
+ render json: @city, scope: current_admin
648
668
  end
649
669
  end
650
670
  ```
@@ -653,3 +673,74 @@ Assuming that the `current_admin` method needs to make a query in the database
653
673
  for the current user, the advantage of this approach is that, by setting
654
674
  `serialization_scope` to `nil`, the `index` action no longer will need to make
655
675
  that query, only the `show` action will.
676
+
677
+ ## Testing
678
+
679
+ In order to test a Serializer, you can just call `.new` on it, passing the object to serialize:
680
+
681
+ ### MiniTest
682
+
683
+ ```ruby
684
+ class TestPostSerializer < Minitest::Test
685
+ def setup
686
+ @serializer = PostSerializer.new Post.new(id: 123, title: 'some title', body: 'some text')
687
+ end
688
+
689
+ def test_special_json_for_api
690
+ assert_equal '{"post":{"id":123,"title":"some title","body":"some text"}}', @serializer.to_json
691
+ end
692
+ ```
693
+
694
+ ### RSpec
695
+
696
+ ```ruby
697
+ describe PostSerializer do
698
+ it "creates special JSON for the API" do
699
+ serializer = PostSerializer.new Post.new(id: 123, title: 'some title', body: 'some text')
700
+ expect(serializer.to_json).to eql('{"post":{"id":123,"title":"some title","body":"some text"}}')
701
+ end
702
+ end
703
+ ```
704
+
705
+ ## Caching
706
+
707
+ NOTE: This functionality was removed from AMS and it's in the TODO list.
708
+ We need to re-think and re-design the caching strategy for the next
709
+ version of AMS.
710
+
711
+ To cache a serializer, call `cached` and define a `cache_key` method:
712
+
713
+ ```ruby
714
+ class PostSerializer < ActiveModel::Serializer
715
+ cached # enables caching for this serializer
716
+
717
+ attributes :title, :body
718
+
719
+ def cache_key
720
+ [object, scope]
721
+ end
722
+ end
723
+ ```
724
+
725
+ The caching interface uses `Rails.cache` under the hood.
726
+
727
+ # Design and Implementation Guidelines
728
+
729
+ ## Keep it Simple
730
+
731
+ `ActiveModel::Serializers` is capable of producing complex JSON views/large object
732
+ trees, and it may be tempting to design in this way so that your client can make
733
+ fewer requests to get data and so that related querying can be optimized.
734
+ However, keeping things simple in your serializers and controllers may
735
+ significantly reduce complexity and maintenance over the long-term development
736
+ of your application. Please consider reducing the complexity of the JSON views
737
+ you provide via the serializers as you build out your application, so that
738
+ controllers/services can be more easily reused without a lot of complexity
739
+ later.
740
+
741
+ ## Performance
742
+
743
+ As you develop your controllers or other code that utilizes serializers, try to
744
+ avoid n+1 queries by ensuring that data loads in an optimal fashion, e.g. if you
745
+ are using ActiveRecord, you might want to use query includes or joins as needed
746
+ to make the data available that the serializer(s) need.