active_model_serializers 0.9.9 → 0.10.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +634 -61
  3. data/MIT-LICENSE +3 -2
  4. data/README.md +194 -846
  5. data/lib/action_controller/serialization.rb +35 -66
  6. data/lib/active_model/serializable_resource.rb +13 -0
  7. data/lib/active_model/serializer/adapter/attributes.rb +17 -0
  8. data/lib/active_model/serializer/adapter/base.rb +20 -0
  9. data/lib/active_model/serializer/adapter/json.rb +17 -0
  10. data/lib/active_model/serializer/adapter/json_api.rb +17 -0
  11. data/lib/active_model/serializer/adapter/null.rb +17 -0
  12. data/lib/active_model/serializer/adapter.rb +26 -0
  13. data/lib/active_model/serializer/array_serializer.rb +14 -0
  14. data/lib/active_model/serializer/association.rb +55 -40
  15. data/lib/active_model/serializer/attribute.rb +27 -0
  16. data/lib/active_model/serializer/belongs_to_reflection.rb +13 -0
  17. data/lib/active_model/serializer/collection_serializer.rb +99 -0
  18. data/lib/active_model/serializer/concerns/caching.rb +305 -0
  19. data/lib/active_model/serializer/error_serializer.rb +16 -0
  20. data/lib/active_model/serializer/errors_serializer.rb +34 -0
  21. data/lib/active_model/serializer/field.rb +92 -0
  22. data/lib/active_model/serializer/fieldset.rb +33 -0
  23. data/lib/active_model/serializer/has_many_reflection.rb +12 -0
  24. data/lib/active_model/serializer/has_one_reflection.rb +9 -0
  25. data/lib/active_model/serializer/lazy_association.rb +99 -0
  26. data/lib/active_model/serializer/link.rb +23 -0
  27. data/lib/active_model/serializer/lint.rb +152 -0
  28. data/lib/active_model/serializer/null.rb +19 -0
  29. data/lib/active_model/serializer/reflection.rb +212 -0
  30. data/lib/active_model/serializer/version.rb +3 -1
  31. data/lib/active_model/serializer.rb +363 -269
  32. data/lib/active_model_serializers/adapter/attributes.rb +36 -0
  33. data/lib/active_model_serializers/adapter/base.rb +85 -0
  34. data/lib/active_model_serializers/adapter/json.rb +23 -0
  35. data/lib/active_model_serializers/adapter/json_api/deserialization.rb +215 -0
  36. data/lib/active_model_serializers/adapter/json_api/error.rb +98 -0
  37. data/lib/active_model_serializers/adapter/json_api/jsonapi.rb +51 -0
  38. data/lib/active_model_serializers/adapter/json_api/link.rb +85 -0
  39. data/lib/active_model_serializers/adapter/json_api/meta.rb +39 -0
  40. data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +94 -0
  41. data/lib/active_model_serializers/adapter/json_api/relationship.rb +106 -0
  42. data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +68 -0
  43. data/lib/active_model_serializers/adapter/json_api.rb +535 -0
  44. data/lib/active_model_serializers/adapter/null.rb +11 -0
  45. data/lib/active_model_serializers/adapter.rb +100 -0
  46. data/lib/active_model_serializers/callbacks.rb +57 -0
  47. data/lib/active_model_serializers/deprecate.rb +56 -0
  48. data/lib/active_model_serializers/deserialization.rb +17 -0
  49. data/lib/active_model_serializers/json_pointer.rb +16 -0
  50. data/lib/active_model_serializers/logging.rb +124 -0
  51. data/lib/active_model_serializers/lookup_chain.rb +82 -0
  52. data/lib/active_model_serializers/model.rb +132 -0
  53. data/lib/active_model_serializers/railtie.rb +52 -0
  54. data/lib/active_model_serializers/register_jsonapi_renderer.rb +80 -0
  55. data/lib/active_model_serializers/serializable_resource.rb +84 -0
  56. data/lib/active_model_serializers/serialization_context.rb +41 -0
  57. data/lib/active_model_serializers/test/schema.rb +140 -0
  58. data/lib/active_model_serializers/test/serializer.rb +127 -0
  59. data/lib/active_model_serializers/test.rb +9 -0
  60. data/lib/active_model_serializers.rb +60 -17
  61. data/lib/generators/rails/USAGE +6 -0
  62. data/lib/{active_model/serializer/generators → generators/rails}/resource_override.rb +3 -4
  63. data/lib/{active_model/serializer/generators/serializer → generators/rails}/serializer_generator.rb +6 -5
  64. data/lib/grape/active_model_serializers.rb +18 -0
  65. data/lib/grape/formatters/active_model_serializers.rb +34 -0
  66. data/lib/grape/helpers/active_model_serializers.rb +19 -0
  67. data/lib/tasks/rubocop.rake +60 -0
  68. metadata +248 -155
  69. data/CONTRIBUTING.md +0 -20
  70. data/DESIGN.textile +0 -586
  71. data/lib/action_controller/serialization_test_case.rb +0 -79
  72. data/lib/active_model/array_serializer.rb +0 -68
  73. data/lib/active_model/default_serializer.rb +0 -28
  74. data/lib/active_model/serializable/utils.rb +0 -16
  75. data/lib/active_model/serializable.rb +0 -59
  76. data/lib/active_model/serializer/association/has_many.rb +0 -39
  77. data/lib/active_model/serializer/association/has_one.rb +0 -25
  78. data/lib/active_model/serializer/config.rb +0 -31
  79. data/lib/active_model/serializer/generators/serializer/USAGE +0 -9
  80. data/lib/active_model/serializer/generators/serializer/scaffold_controller_generator.rb +0 -14
  81. data/lib/active_model/serializer/generators/serializer/templates/controller.rb +0 -93
  82. data/lib/active_model/serializer/railtie.rb +0 -22
  83. data/lib/active_model/serializer_support.rb +0 -5
  84. data/test/benchmark/app.rb +0 -60
  85. data/test/benchmark/benchmarking_support.rb +0 -67
  86. data/test/benchmark/bm_active_record.rb +0 -41
  87. data/test/benchmark/setup.rb +0 -75
  88. data/test/benchmark/tmp/miniprofiler/mp_timers_6eqewtfgrhitvq5gqm25 +0 -0
  89. data/test/benchmark/tmp/miniprofiler/mp_timers_8083sx03hu72pxz1a4d0 +0 -0
  90. data/test/benchmark/tmp/miniprofiler/mp_timers_fyz2gsml4z0ph9kpoy1c +0 -0
  91. data/test/benchmark/tmp/miniprofiler/mp_timers_hjry5rc32imd42oxoi48 +0 -0
  92. data/test/benchmark/tmp/miniprofiler/mp_timers_m8fpoz2cvt3g9agz0bs3 +0 -0
  93. data/test/benchmark/tmp/miniprofiler/mp_timers_p92m2drnj1i568u3sta0 +0 -0
  94. data/test/benchmark/tmp/miniprofiler/mp_timers_qg52tpca3uesdfguee9i +0 -0
  95. data/test/benchmark/tmp/miniprofiler/mp_timers_s15t1a6mvxe0z7vjv790 +0 -0
  96. data/test/benchmark/tmp/miniprofiler/mp_timers_x8kal3d17nfds6vp4kcj +0 -0
  97. data/test/benchmark/tmp/miniprofiler/mp_views_127.0.0.1 +0 -0
  98. data/test/fixtures/active_record.rb +0 -96
  99. data/test/fixtures/poro.rb +0 -254
  100. data/test/fixtures/template.html.erb +0 -1
  101. data/test/integration/action_controller/namespaced_serialization_test.rb +0 -105
  102. data/test/integration/action_controller/serialization_test.rb +0 -287
  103. data/test/integration/action_controller/serialization_test_case_test.rb +0 -71
  104. data/test/integration/active_record/active_record_test.rb +0 -94
  105. data/test/integration/generators/resource_generator_test.rb +0 -26
  106. data/test/integration/generators/scaffold_controller_generator_test.rb +0 -64
  107. data/test/integration/generators/serializer_generator_test.rb +0 -41
  108. data/test/test_app.rb +0 -14
  109. data/test/test_helper.rb +0 -26
  110. data/test/tmp/app/assets/javascripts/accounts.js +0 -2
  111. data/test/tmp/app/assets/stylesheets/accounts.css +0 -4
  112. data/test/tmp/app/controllers/accounts_controller.rb +0 -3
  113. data/test/tmp/app/helpers/accounts_helper.rb +0 -3
  114. data/test/tmp/app/serializers/account_serializer.rb +0 -4
  115. data/test/tmp/config/routes.rb +0 -2
  116. data/test/unit/active_model/array_serializer/except_test.rb +0 -18
  117. data/test/unit/active_model/array_serializer/key_format_test.rb +0 -18
  118. data/test/unit/active_model/array_serializer/meta_test.rb +0 -53
  119. data/test/unit/active_model/array_serializer/only_test.rb +0 -18
  120. data/test/unit/active_model/array_serializer/options_test.rb +0 -16
  121. data/test/unit/active_model/array_serializer/root_test.rb +0 -102
  122. data/test/unit/active_model/array_serializer/scope_test.rb +0 -24
  123. data/test/unit/active_model/array_serializer/serialization_test.rb +0 -239
  124. data/test/unit/active_model/default_serializer_test.rb +0 -13
  125. data/test/unit/active_model/serializer/associations/build_serializer_test.rb +0 -36
  126. data/test/unit/active_model/serializer/associations_test.rb +0 -49
  127. data/test/unit/active_model/serializer/attributes_test.rb +0 -57
  128. data/test/unit/active_model/serializer/config_test.rb +0 -91
  129. data/test/unit/active_model/serializer/filter_test.rb +0 -69
  130. data/test/unit/active_model/serializer/has_many_polymorphic_test.rb +0 -189
  131. data/test/unit/active_model/serializer/has_many_test.rb +0 -265
  132. data/test/unit/active_model/serializer/has_one_and_has_many_test.rb +0 -27
  133. data/test/unit/active_model/serializer/has_one_polymorphic_test.rb +0 -196
  134. data/test/unit/active_model/serializer/has_one_test.rb +0 -253
  135. data/test/unit/active_model/serializer/key_format_test.rb +0 -25
  136. data/test/unit/active_model/serializer/meta_test.rb +0 -39
  137. data/test/unit/active_model/serializer/options_test.rb +0 -42
  138. data/test/unit/active_model/serializer/root_test.rb +0 -117
  139. data/test/unit/active_model/serializer/scope_test.rb +0 -49
  140. data/test/unit/active_model/serializer/url_helpers_test.rb +0 -35
  141. data/test/unit/active_model/serilizable_test.rb +0 -50
  142. /data/lib/{active_model/serializer/generators/serializer/templates/serializer.rb → generators/rails/templates/serializer.rb.erb} +0 -0
data/README.md CHANGED
@@ -1,956 +1,304 @@
1
- [![Build Status](https://api.travis-ci.org/rails-api/active_model_serializers.png?branch=0-9-stable)](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)
1
+ # ActiveModelSerializers
3
2
 
4
- # ActiveModel::Serializers
3
+ <table>
4
+ <tr>
5
+ <td>Build Status</td>
6
+ <td>
7
+ <a href="https://github.com/rails-api/active_model_serializers/actions"><img src="https://github.com/rails-api/active_model_serializers/actions/workflows/ci.yml/badge.svg?branch=0-10-stable" alt="Build Status" ></a>
8
+ <a href="https://ci.appveyor.com/project/bf4/active-model-serializers/branch/0-10-stable"><img src="https://ci.appveyor.com/api/projects/status/x6xdjydutm54gvyt/branch/master?svg=true" alt="Build status"></a>
9
+ </td>
10
+ </tr>
11
+ <tr>
12
+ <td>Code Quality</td>
13
+ <td>
14
+ <a href="https://codeclimate.com/github/rails-api/active_model_serializers"><img src="https://codeclimate.com/github/rails-api/active_model_serializers/badges/gpa.svg" alt="Code Quality"></a>
15
+ <a href="https://codebeat.co/projects/github-com-rails-api-active_model_serializers"><img src="https://codebeat.co/badges/a9ab35fa-8b5a-4680-9d4e-a81f9a55ebcd" alt="codebeat" ></a>
16
+ </td>
17
+ </tr>
18
+ <tr>
19
+ <td>Issue Stats</td>
20
+ <td>
21
+ <a href="https://github.com/rails-api/active_model_serializers/pulse/monthly">Pulse</a>
22
+ </td>
23
+ </tr>
24
+ </table>
5
25
 
6
- ## Purpose
26
+ ## About
7
27
 
8
- `ActiveModel::Serializers` encapsulates the JSON serialization of objects.
9
- Objects that respond to read\_attribute\_for\_serialization
10
- (including `ActiveModel` and `ActiveRecord` objects) are supported.
28
+ ActiveModelSerializers brings convention over configuration to your JSON generation.
11
29
 
12
- Serializers know about both a model and the `current_user`, so you can
13
- customize serialization based upon whether a user is authorized to see the
14
- content.
30
+ ActiveModelSerializers works through two components: **serializers** and **adapters**.
15
31
 
16
- In short, **serializers replace hash-driven development with object-oriented
17
- development.**
32
+ Serializers describe _which_ attributes and relationships should be serialized.
18
33
 
19
- # Installing
34
+ Adapters describe _how_ attributes and relationships should be serialized.
20
35
 
21
- The easiest way to install `ActiveModel::Serializers` is to add it to your
22
- `Gemfile`:
36
+ SerializableResource co-ordinates the resource, Adapter and Serializer to produce the
37
+ resource serialization. The serialization has the `#as_json`, `#to_json` and `#serializable_hash`
38
+ methods used by the Rails JSON Renderer. (SerializableResource actually delegates
39
+ these methods to the adapter.)
23
40
 
24
- ```ruby
25
- gem "active_model_serializers"
26
- ```
27
-
28
- Then, install it on the command line:
29
-
30
- ```
31
- $ bundle install
32
- ```
33
-
34
- #### Ruby 1.8 is no longer supported!
35
-
36
- 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.
37
- Versions after 0.9.0 do not support ruby 1.8. To specify version 0.8, include this in your Gemfile:
38
-
39
- ```ruby
40
- gem "active_model_serializers", "~> 0.8.0"
41
- ```
42
-
43
-
44
- # Creating a Serializer
45
-
46
- The easiest way to create a new serializer is to generate a new resource, which
47
- will generate a serializer at the same time:
48
-
49
- ```
50
- $ rails g resource post title:string body:string
51
- ```
52
-
53
- This will generate a serializer in `app/serializers/post_serializer.rb` for
54
- your new model. You can also generate a serializer for an existing model with
55
- the serializer generator:
56
-
57
- ```
58
- $ rails g serializer post
59
- ```
60
-
61
- ### Support for POROs
62
-
63
- The PORO should include ActiveModel::SerializerSupport. That's all you need to
64
- do to have your POROs supported.
65
-
66
- For Rails versions before Rails 4 ActiveModel::Serializers expects objects to
67
- implement `read_attribute_for_serialization`.
68
-
69
- # render :json
70
-
71
- In your controllers, when you use `render :json`, Rails will now first search
72
- for a serializer for the object and use it if available.
73
-
74
- ```ruby
75
- class PostsController < ApplicationController
76
- def show
77
- @post = Post.find(params[:id])
78
- render json: @post
79
- end
80
- end
81
- ```
82
-
83
- In this case, Rails will look for a serializer named `PostSerializer`, and if
84
- it exists, use it to serialize the `Post`.
85
-
86
- This also works with `respond_with`, which uses `to_json` under the hood. Also
87
- note that any options passed to `render :json` will be passed to your
88
- serializer and available as `@serialization_options` inside.
89
-
90
- To specify a custom serializer for an object, you can specify the
91
- serializer when you render the object:
92
-
93
- ```ruby
94
- render json: @post, serializer: FancyPostSerializer
95
- ```
96
-
97
- ### Use serialization outside of ActionController::Base
98
-
99
- When controller does not inherit from ActionController::Base,
100
- include Serialization module manually:
101
-
102
- ```ruby
103
- class ApplicationController < ActionController::API
104
- include ActionController::Serialization
105
- end
106
- ```
107
-
108
- ## Arrays
109
-
110
- In your controllers, when you use `render :json` for an array of objects, AMS will
111
- use `ActiveModel::ArraySerializer` (included in this project) as the base serializer,
112
- and the individual `Serializer` for the objects contained in that array.
113
-
114
- ```ruby
115
- class PostSerializer < ActiveModel::Serializer
116
- attributes :title, :body
117
- end
118
-
119
- class PostsController < ApplicationController
120
- def index
121
- @posts = Post.all
122
- render json: @posts
123
- end
124
- end
125
- ```
126
-
127
- Given the example above, the index action will return
128
-
129
- ```json
130
- {
131
- "posts":
132
- [
133
- { "title": "Post 1", "body": "Hello!" },
134
- { "title": "Post 2", "body": "Goodbye!" }
135
- ]
136
- }
137
- ```
138
-
139
- By default, the root element is the name of the controller. For example, `PostsController`
140
- generates a root element "posts". To change it:
141
-
142
- ```ruby
143
- render json: @posts, root: "some_posts"
144
- ```
145
-
146
- You may disable the root element for arrays at the top level, which will result in
147
- more concise json. See the next section for ways on how to do this. Disabling the
148
- root element of the array with any of those methods will produce
149
-
150
- ```json
151
- [
152
- { "title": "Post 1", "body": "Hello!" },
153
- { "title": "Post 2", "body": "Goodbye!" }
154
- ]
155
- ```
156
-
157
- To specify a custom serializer for the items within an array:
158
-
159
- ```ruby
160
- render json: @posts, each_serializer: FancyPostSerializer
161
- ```
162
-
163
- ## Render independently
164
-
165
- By default the setting of serializer is in controller as described above which is the
166
- recommended way. However, there may be cases you need to render the json object elsewhere
167
- say in a helper or a view when controller is only for main object.
168
-
169
- Then you can render the serialized JSON independently.
170
-
171
- ```ruby
172
- def current_user_as_json_helper
173
- CurrentUserSerializer.new(current_user).to_json
174
- end
175
- ```
176
-
177
- You can also render an array of objects using ArraySerializer.
178
-
179
- ```ruby
180
- def users_array_as_json_helper(users)
181
- ActiveModel::ArraySerializer.new(users, each_serializer: UserSerializer).to_json
182
- end
183
- ```
184
-
185
-
186
- ## Disabling the root element
187
-
188
- You have 4 options to disable the root element, each with a slightly different scope:
189
-
190
- #### 1. Disable root globally for all, or per class
191
-
192
- In an initializer:
193
-
194
- ```ruby
195
- # Disable for all serializers (except ArraySerializer)
196
- ActiveModel::Serializer.root = false
197
-
198
- # Disable for ArraySerializer
199
- ActiveModel::ArraySerializer.root = false
200
- ```
201
-
202
- #### 2. Disable root per render call in your controller
203
-
204
- ```ruby
205
- render json: @posts, root: false
206
- ```
207
-
208
- #### 3. Subclass the serializer, and specify using it
209
-
210
- ```ruby
211
- class CustomArraySerializer < ActiveModel::ArraySerializer
212
- self.root = false
213
- end
214
-
215
- # controller:
216
- render json: @posts, serializer: CustomArraySerializer
217
- ```
218
-
219
- #### 4. Define default_serializer_options in your controller
220
-
221
- If you define `default_serializer_options` method in your controller,
222
- all serializers in actions of this controller and it's children will use them.
223
- One of the options may be `root: false`
224
-
225
- ```ruby
226
- def default_serializer_options
227
- {
228
- root: false
229
- }
230
- end
231
- ```
232
-
233
- ## Changing the Key Format
234
-
235
- You can specify that serializers use the lower-camel key format at the config, class or instance level.
236
-
237
- ```ruby
238
-
239
- ActiveModel::Serializer.setup do |config|
240
- config.key_format = :lower_camel
241
- end
242
-
243
- class BlogLowerCamelSerializer < ActiveModel::Serializer
244
- format_keys :lower_camel
245
- end
246
-
247
- BlogSerializer.new(object, key_format: :lower_camel)
248
- ```
249
-
250
- ## Changing the default association key type
251
-
252
- You can specify that serializers use unsuffixed names as association keys by default.
253
-
254
- ```ruby
255
- ActiveModel::Serializer.setup do |config|
256
- config.default_key_type = :name
257
- end
258
- ```
259
-
260
- This will build association keys like `comments` or `author` instead of `comment_ids` or `author_id`.
261
-
262
- ## Getting the old version
263
-
264
- If you find that your project is already relying on the old rails to_json
265
- change `render :json` to `render json: @your_object.to_json`.
266
-
267
- # Attributes and Associations
268
-
269
- Once you have a serializer, you can specify which attributes and associations
270
- you would like to include in the serialized form.
271
-
272
- ```ruby
273
- class PostSerializer < ActiveModel::Serializer
274
- attributes :id, :title, :body
275
- has_many :comments
276
- end
277
- ```
41
+ By default ActiveModelSerializers will use the **Attributes Adapter** (no JSON root).
42
+ But we strongly advise you to use **JsonApi Adapter**, which
43
+ follows 1.0 of the format specified in [jsonapi.org/format](https://jsonapi.org/format).
44
+ Check how to change the adapter in the sections below.
278
45
 
279
- ## Attributes
46
+ `0.10.x` is **not** backward compatible with `0.9.x` nor `0.8.x`.
280
47
 
281
- For specified attributes, a serializer will look up the attribute on the
282
- object you passed to `render :json`. It uses
283
- `read_attribute_for_serialization`, which `ActiveRecord` objects implement as a
284
- regular attribute lookup.
48
+ `0.10.x` is based on the `0.8.0` code, but with a more flexible
49
+ architecture. We'd love your help. [Learn how you can help here.](CONTRIBUTING.md)
285
50
 
286
- Before looking up the attribute on the object, a serializer will check for the
287
- presence of a method with the name of the attribute. This allows serializers to
288
- include properties beyond the simple attributes of the model. For example:
51
+ ## Installation
289
52
 
290
- ```ruby
291
- class PersonSerializer < ActiveModel::Serializer
292
- attributes :first_name, :last_name, :full_name
53
+ Add this line to your application's Gemfile:
293
54
 
294
- def full_name
295
- "#{object.first_name} #{object.last_name}"
296
- end
297
- end
298
55
  ```
299
-
300
- Within a serializer's methods, you can access the object being
301
- serialized as `object`.
302
-
303
- Since this shadows any attribute named `object`, you can include them through `object.object`. For example:
304
-
305
- ```ruby
306
- class VersionSerializer < ActiveModel::Serializer
307
- attributes :version_object
308
-
309
- def version_object
310
- object.object
311
- end
312
- end
56
+ gem 'active_model_serializers', '~> 0.10.0'
313
57
  ```
314
58
 
315
- You can also access the `scope` method, which provides an
316
- authorization context to your serializer. By default, the context
317
- is the current user of your application, but this
318
- [can be customized](#customizing-scope).
59
+ And then execute:
319
60
 
320
- Serializers provide a method named `filter`, which should return an array
321
- used to determine what attributes and associations should be included in the output.
322
- This is typically used to customize output based on `current_user`. For example:
323
-
324
- ```ruby
325
- class PostSerializer < ActiveModel::Serializer
326
- attributes :id, :title, :body, :author
327
-
328
- def filter(keys)
329
- if scope.admin?
330
- keys
331
- else
332
- keys - [:author]
333
- end
334
- end
335
- end
336
61
  ```
337
-
338
- And it's also safe to mutate keys argument by doing keys.delete(:author)
339
- in case you want to avoid creating two extra arrays. Note that if you do an
340
- in-place modification, you still need to return the modified array.
341
-
342
- ### Alias Attribute
343
- If you would like the key in the outputted JSON to be different from its name
344
- in ActiveRecord, you can declare the attribute with the different name
345
- and redefine that method:
346
-
347
- ```ruby
348
- class PostSerializer < ActiveModel::Serializer
349
- # look up subject on the model, but use title in the JSON
350
- def title
351
- object.subject
352
- end
353
-
354
- attributes :id, :body, :title
355
- has_many :comments
356
- end
62
+ $ bundle
357
63
  ```
358
64
 
359
- If you would like to add meta information to the outputted JSON, use the `:meta`
360
- option:
65
+ ## Getting Started
361
66
 
362
- ```ruby
363
- render json: @posts, serializer: CustomArraySerializer, meta: {total: 10}
364
- ```
67
+ See [Getting Started](docs/general/getting_started.md) for the nuts and bolts.
365
68
 
366
- The above usage of `:meta` will produce the following:
69
+ More information is available in the [Guides](docs) and
70
+ [High-level behavior](README.md#high-level-behavior).
367
71
 
368
- ```json
369
- {
370
- "meta": { "total": 10 },
371
- "posts": [
372
- { "title": "Post 1", "body": "Hello!" },
373
- { "title": "Post 2", "body": "Goodbye!" }
374
- ]
375
- }
376
- ```
72
+ ## Getting Help
377
73
 
378
- If you would like to change the meta key name you can use the `:meta_key` option:
74
+ If you find a bug, please report an [Issue](https://github.com/rails-api/active_model_serializers/issues/new)
75
+ and see our [contributing guide](CONTRIBUTING.md).
379
76
 
380
- ```ruby
381
- render json: @posts, serializer: CustomArraySerializer, meta_object: { total: 10 }, meta_key: :meta_object
382
- ```
77
+ If you have a question, please [post to Stack Overflow](https://stackoverflow.com/questions/tagged/active-model-serializers).
383
78
 
384
- The above usage of `:meta_key` will produce the following:
79
+ If you'd like to chat, we have a [community slack](https://amserializers.herokuapp.com).
385
80
 
386
- ```json
387
- {
388
- "meta_object": { "total": 10 },
389
- "posts": [
390
- { "title": "Post 1", "body": "Hello!" },
391
- { "title": "Post 2", "body": "Goodbye!" }
392
- ]
393
- }
394
- ```
81
+ Thanks!
395
82
 
396
- When using meta information, your serializer cannot have the `{ root: false }` option, as this would lead to
397
- invalid JSON. If you do not have a root key, the meta information will be ignored.
83
+ ## Documentation
398
84
 
399
- If you would like direct, low-level control of attribute serialization, you can
400
- completely override the `attributes` method to return the hash you need:
85
+ If you're reading this at https://github.com/rails-api/active_model_serializers you are
86
+ reading documentation for our `master`, which may include features that have not
87
+ been released yet. Please see below for the documentation relevant to you.
401
88
 
402
- ```ruby
403
- class PersonSerializer < ActiveModel::Serializer
404
- attributes :first_name, :last_name
405
-
406
- def attributes
407
- hash = super
408
- if scope.admin?
409
- hash["ssn"] = object.ssn
410
- hash["secret"] = object.mothers_maiden_name
411
- end
412
- hash
413
- end
414
- end
415
- ```
89
+ - [0.10 (0-10-stable) Documentation](https://github.com/rails-api/active_model_serializers/tree/0-10-stable)
90
+ - [0.10.10 (latest release) Documentation](https://github.com/rails-api/active_model_serializers/tree/v0.10.10)
91
+ - [![API Docs](https://img.shields.io/badge/yard-docs-blue.svg)](https://www.rubydoc.info/gems/active_model_serializers/0.10.10)
92
+ - [Guides](docs)
93
+ - [0.9 (0-9-stable) Documentation](https://github.com/rails-api/active_model_serializers/tree/0-9-stable)
94
+ - [![API Docs](https://img.shields.io/badge/yard-docs-blue.svg)](https://www.rubydoc.info/gems/active_model_serializers/0.9.7)
95
+ - [0.8 (0-8-stable) Documentation](https://github.com/rails-api/active_model_serializers/tree/0-8-stable)
96
+ - [![API Docs](https://img.shields.io/badge/yard-docs-blue.svg)](https://www.rubydoc.info/gems/active_model_serializers/0.8.4)
416
97
 
417
- ## Associations
418
98
 
419
- For specified associations, the serializer will look up the association and
420
- then serialize each element of the association. For instance, a `has_many
421
- :comments` association will create a new `CommentSerializer` for each comment
422
- and use it to serialize the comment.
99
+ ## High-level behavior
423
100
 
424
- By default, serializers simply look up the association on the original object.
425
- You can customize this behavior by implementing a method with the name of the
426
- association and returning a different Array. Often, you will do this to
427
- customize the objects returned based on the current user (scope).
101
+ Choose an adapter from [adapters](lib/active_model_serializers/adapter):
428
102
 
429
- ```ruby
430
- class PostSerializer < ActiveModel::Serializer
431
- attributes :id, :title, :body
432
- has_many :comments
433
-
434
- # only let the user see comments he created.
435
- def comments
436
- object.comments.where(created_by: scope)
437
- end
438
- end
103
+ ``` ruby
104
+ ActiveModelSerializers.config.adapter = :json_api # Default: `:attributes`
439
105
  ```
440
106
 
441
- As with attributes, you can change the JSON key that the serializer should
442
- use for a particular association.
107
+ Given a [serializable model](lib/active_model/serializer/lint.rb):
443
108
 
444
109
  ```ruby
445
- class PostSerializer < ActiveModel::Serializer
446
- attributes :id, :title, :body
447
-
448
- # look up comments, but use +my_comments+ as the key in JSON
449
- has_many :comments, root: :my_comments
110
+ # either
111
+ class SomeResource < ActiveRecord::Base
112
+ # columns: title, body
450
113
  end
451
- ```
452
-
453
- Also, as with attributes, serializers will execute a filter method to
454
- determine which associations should be included in the output. For
455
- example:
456
-
457
- ```ruby
458
- class PostSerializer < ActiveModel::Serializer
459
- attributes :id, :title, :body
460
- has_many :comments
461
-
462
- def filter(keys)
463
- keys.delete :comments if object.comments_disabled?
464
- keys
465
- end
466
- end
467
- ```
468
-
469
- Or ...
470
-
471
- ```ruby
472
- class PostSerializer < ActiveModel::Serializer
473
- attributes :id, :title, :body
474
- has_one :author
475
- has_many :comments
476
-
477
- def filter(keys)
478
- keys.delete :author unless scope.admin?
479
- keys.delete :comments if object.comments_disabled?
480
- keys
481
- end
482
- end
483
- ```
484
-
485
- 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.:
486
-
487
- ```ruby
488
- has_many :comments, serializer: CommentShortSerializer
489
- has_one :reviewer, polymorphic: true
490
- ```
491
-
492
- Serializers are only concerned with multiplicity, and not ownership. `belongs_to` ActiveRecord associations can be included using `has_one` in your serializer.
493
-
494
- ## Embedding Associations
495
-
496
- By default, associations will be embedded inside the serialized object. So if
497
- you have a post, the outputted JSON will look like:
498
-
499
- ```json
500
- {
501
- "post": {
502
- "id": 1,
503
- "title": "New post",
504
- "body": "A body!",
505
- "comments": [
506
- { "id": 1, "body": "what a dumb post" }
507
- ]
508
- }
509
- }
510
- ```
511
-
512
- This is convenient for simple use-cases, but for more complex clients, it is
513
- better to supply an Array of IDs for the association. This makes your API more
514
- flexible from a performance standpoint and avoids wasteful duplication.
515
-
516
- To embed IDs instead of associations, simply use the `embed` class method:
517
-
518
- ```ruby
519
- class PostSerializer < ActiveModel::Serializer
520
- embed :ids
521
-
522
- attributes :id, :title, :body
523
- has_many :comments
524
- end
525
- ```
526
-
527
- Now, any associations will be supplied as an Array of IDs:
528
-
529
- ```json
530
- {
531
- "post": {
532
- "id": 1,
533
- "title": "New post",
534
- "body": "A body!",
535
- "comment_ids": [ 1, 2, 3 ]
536
- }
537
- }
538
- ```
539
-
540
- You may also choose to embed the IDs by the association's name underneath a
541
- `key` for the resource. For example, say we want to change `comment_ids`
542
- to `comments` underneath a `links` key:
543
-
544
- ```ruby
545
- class PostSerializer < ActiveModel::Serializer
546
- attributes :id, :title, :body
547
-
548
- has_many :comments, embed: :ids, key: :comments, embed_namespace: :links
114
+ # or
115
+ class SomeResource < ActiveModelSerializers::Model
116
+ attributes :title, :body
549
117
  end
550
118
  ```
551
119
 
552
- The JSON will look like this:
553
-
554
- ```json
555
- {
556
- "post": {
557
- "id": 1,
558
- "title": "New post",
559
- "body": "A body!",
560
- "links": {
561
- "comments": [ 1, 2, 3 ]
562
- }
563
- }
564
- }
565
- ```
566
-
567
- Alternatively, you can choose to embed only the ids or the associated objects per association:
120
+ And initialized as:
568
121
 
569
122
  ```ruby
570
- class PostSerializer < ActiveModel::Serializer
571
- attributes :id, :title, :body
572
-
573
- has_many :comments, embed: :objects
574
- has_many :tags, embed: :ids
575
- end
576
- ```
577
-
578
- The JSON will look like this:
579
-
580
- ```json
581
- {
582
- "post": {
583
- "id": 1,
584
- "title": "New post",
585
- "body": "A body!",
586
- "comments": [
587
- { "id": 1, "body": "what a dumb post" }
588
- ],
589
- "tag_ids": [ 1, 2, 3 ]
590
- }
591
- }
123
+ resource = SomeResource.new(title: 'ActiveModelSerializers', body: 'Convention over configuration')
592
124
  ```
593
125
 
594
- In addition to supplying an Array of IDs, you may want to side-load the data
595
- alongside the main object. This makes it easier to process the entire package
596
- of data without having to recursively scan the tree looking for embedded
597
- information. It also ensures that associations that are shared between several
598
- objects (like tags), are only delivered once for the entire payload.
599
-
600
- You can specify that the data be included like this:
126
+ Given a serializer for the serializable model:
601
127
 
602
128
  ```ruby
603
- class PostSerializer < ActiveModel::Serializer
604
- embed :ids, include: true
605
-
606
- attributes :id, :title, :body
607
- has_many :comments
129
+ class SomeSerializer < ActiveModel::Serializer
130
+ attribute :title, key: :name
131
+ attributes :body
608
132
  end
609
133
  ```
610
134
 
611
- Assuming that the comments also `has_many :tags`, you will get a JSON like
612
- this:
613
-
614
- ```json
615
- {
616
- "post": {
617
- "id": 1,
618
- "title": "New post",
619
- "body": "A body!",
620
- "comment_ids": [ 1, 2 ]
621
- },
622
- "comments": [
623
- { "id": 1, "body": "what a dumb post", "tag_ids": [ 1, 2 ] },
624
- { "id": 2, "body": "i liked it", "tag_ids": [ 1, 3 ] },
625
- ],
626
- "tags": [
627
- { "id": 1, "name": "short" },
628
- { "id": 2, "name": "whiny" },
629
- { "id": 3, "name": "happy" }
630
- ]
631
- }
632
- ```
633
-
634
- If you would like to namespace association JSON underneath a certain key in
635
- the root document (say, `linked`), you can specify an `embed_in_root_key`:
135
+ The model can be serialized as:
636
136
 
637
137
  ```ruby
638
- class PostSerializer < ActiveModel::Serializer
639
- embed :ids, include: true, embed_in_root_key: :linked
640
-
641
- attributes: :id, :title, :body
642
- has_many :comments, :tags
643
- end
644
- ```
645
-
646
- The above would yield the following JSON document:
647
-
648
- ```json
649
- {
650
- "post": {
651
- "id": 1,
652
- "title": "New post",
653
- "body": "A body!",
654
- "comment_ids": [ 1, 2 ]
655
- },
656
- "linked": {
657
- "comments": [
658
- { "id": 1, "body": "what a dumb post", "tag_ids": [ 1, 2 ] },
659
- { "id": 2, "body": "i liked it", "tag_ids": [ 1, 3 ] },
660
- ],
661
- "tags": [
662
- { "id": 1, "name": "short" },
663
- { "id": 2, "name": "whiny" },
664
- { "id": 3, "name": "happy" }
665
- ]
666
- }
667
- }
138
+ options = {}
139
+ serialization = ActiveModelSerializers::SerializableResource.new(resource, options)
140
+ serialization.to_json
141
+ serialization.as_json
668
142
  ```
669
143
 
670
- When side-loading data, your serializer cannot have the `{ root: false }` option,
671
- as this would lead to invalid JSON. If you do not have a root key, the `include`
672
- instruction will be ignored
673
-
674
- You can also specify a different root for the embedded objects than the key
675
- used to reference them:
144
+ SerializableResource delegates to the adapter, which it builds as:
676
145
 
677
146
  ```ruby
678
- class PostSerializer < ActiveModel::Serializer
679
- embed :ids, include: true
680
-
681
- attributes :id, :title, :body
682
- has_many :comments, key: :comment_ids, root: :comment_objects
683
- end
684
- ```
685
-
686
- This would generate JSON that would look like this:
687
-
688
- ```json
689
- {
690
- "post": {
691
- "id": 1,
692
- "title": "New post",
693
- "body": "A body!",
694
- "comment_ids": [ 1 ]
695
- },
696
- "comment_objects": [
697
- { "id": 1, "body": "what a dumb post" }
698
- ]
699
- }
147
+ adapter_options = {}
148
+ adapter = ActiveModelSerializers::Adapter.create(serializer, adapter_options)
149
+ adapter.to_json
150
+ adapter.as_json
151
+ adapter.serializable_hash
700
152
  ```
701
153
 
702
- You can also specify a different attribute to use rather than the ID of the
703
- objects:
154
+ The adapter formats the serializer's attributes and associations (a.k.a. includes):
704
155
 
705
156
  ```ruby
706
- class PostSerializer < ActiveModel::Serializer
707
- embed :ids, include: true
708
-
709
- attributes :id, :title, :body
710
- has_many :comments, key: :external_id
711
- end
157
+ serializer_options = {}
158
+ serializer = SomeSerializer.new(resource, serializer_options)
159
+ serializer.attributes
160
+ serializer.associations
712
161
  ```
713
162
 
714
- This would generate JSON that would look like this:
715
-
716
- ```json
717
- {
718
- "post": {
719
- "id": 1,
720
- "title": "New post",
721
- "body": "A body!",
722
- "comment_ids": [ "COMM001" ]
723
- },
724
- "comments": [
725
- { "id": 1, "external_id": "COMM001", "body": "what a dumb post" }
726
- ]
727
- }
728
- ```
163
+ ## Architecture
729
164
 
730
- **NOTE**: The `embed :ids` mechanism is primary useful for clients that process
731
- data in bulk and load it into a local store. For these clients, the ability to
732
- easily see all of the data per type, rather than having to recursively scan the
733
- data looking for information, is extremely useful.
165
+ This section focuses on architecture the 0.10.x version of ActiveModelSerializers. If you are interested in the architecture of the 0.8 or 0.9 versions,
166
+ please refer to the [0.8 README](https://github.com/rails-api/active_model_serializers/blob/0-8-stable/README.md) or
167
+ [0.9 README](https://github.com/rails-api/active_model_serializers/blob/0-9-stable/README.md).
734
168
 
735
- If you are mostly working with the data in simple scenarios and manually making
736
- Ajax requests, you probably just want to use the default embedded behavior.
169
+ The original design is also available [here](https://github.com/rails-api/active_model_serializers/blob/d72b66d4c5355b0ff0a75a04895fcc4ea5b0c65e/README.textile).
737
170
 
171
+ ### ActiveModel::Serializer
738
172
 
739
- ## Embedding Polymorphic Associations
173
+ An **`ActiveModel::Serializer`** wraps a [serializable resource](https://github.com/rails/rails/blob/master/activemodel/lib/active_model/serialization.rb)
174
+ and exposes an `attributes` method, among a few others.
175
+ It allows you to specify which attributes and associations should be represented in the serializatation of the resource.
176
+ It requires an adapter to transform its attributes into a JSON document; it cannot be serialized itself.
177
+ It may be useful to think of it as a
178
+ [presenter](https://blog.steveklabnik.com/posts/2011-09-09-better-ruby-presenters).
740
179
 
741
- Because we need both the id and the type to be able to identify a polymorphic associated model, these are serialized in a slightly different format than common ones.
180
+ #### ActiveModel::CollectionSerializer
742
181
 
743
- When embedding entire objects:
182
+ The **`ActiveModel::CollectionSerializer`** represents a collection of resources as serializers
183
+ and, if there is no serializer, primitives.
744
184
 
745
- ```ruby
746
- class PostSerializer < ActiveModel::Serializer
747
- attributes :id, :title
748
- has_many :attachments, polymorphic: true
749
- end
750
- ```
751
-
752
- ```json
753
- {
754
- "post": {
755
- "id": 1,
756
- "title": "New post",
757
- "attachments": [
758
- {
759
- "type": "image",
760
- "image": {
761
- "id": 3,
762
- "name": "logo",
763
- "url": "http://images.com/logo.jpg"
764
- }
765
- },
766
- {
767
- "type": "video",
768
- "video": {
769
- "id": 12,
770
- "uid": "XCSSMDFWW",
771
- "source": "youtube"
772
- }
773
- }
774
- ]
775
- }
776
- }
777
- ```
778
-
779
- When embedding ids:
780
-
781
- ```ruby
782
- class PostSerializer < ActiveModel::Serializer
783
- embed :ids
185
+ ### ActiveModelSerializers::Adapter::Base
784
186
 
785
- attributes :id, :title
786
- has_many :attachments, polymorphic: true
787
- end
788
- ```
187
+ The **`ActiveModelSerializers::Adapter::Base`** describes the structure of the JSON document generated from a
188
+ serializer. For example, the `Attributes` example represents each serializer as its
189
+ unmodified attributes. The `JsonApi` adapter represents the serializer as a [JSON
190
+ API](https://jsonapi.org/) document.
789
191
 
790
- ```json
791
- {
792
- "post": {
793
- "id": 1,
794
- "title": "New post",
795
- "attachment_ids": [
796
- {
797
- "type": "image",
798
- "id": 12
799
- },
800
- {
801
- "type": "video",
802
- "id": 3
803
- }
804
- ]
805
- }
806
- }
807
- ```
192
+ ### ActiveModelSerializers::SerializableResource
808
193
 
194
+ The **`ActiveModelSerializers::SerializableResource`** acts to coordinate the serializer(s) and adapter
195
+ to an object that responds to `to_json`, and `as_json`. It is used in the controller to
196
+ encapsulate the serialization resource when rendered. However, it can also be used on its own
197
+ to serialize a resource outside of a controller, as well.
809
198
 
810
- ## Customizing Scope
199
+ ### Primitive handling
811
200
 
812
- In a serializer, `current_user` is the current authorization scope which the controller
813
- provides to the serializer when you call `render :json`. By default, this is
814
- `current_user`, but can be customized in your controller by calling
815
- `serialization_scope`:
201
+ Definitions: A primitive is usually a String or Array. There is no serializer
202
+ defined for them; they will be serialized when the resource is converted to JSON (`as_json` or
203
+ `to_json`). (The below also applies for any object with no serializer.)
816
204
 
817
- ```ruby
818
- class ApplicationController < ActionController::Base
819
- serialization_scope :current_admin
820
- end
821
- ```
205
+ - ActiveModelSerializers doesn't handle primitives passed to `render json:` at all.
822
206
 
823
- The above example will also change the scope from `current_user` to
824
- `current_admin`.
207
+ Internally, if no serializer can be found in the controller, the resource is not decorated by
208
+ ActiveModelSerializers.
825
209
 
826
- Please note that, until now, `serialization_scope` doesn't accept a second
827
- object with options for specifying which actions should or should not take a
828
- given scope in consideration.
210
+ - However, when a primitive value is an attribute or in a collection, it is not modified.
829
211
 
830
- To be clear, it's not possible, yet, to do something like this:
212
+ When serializing a collection and the collection serializer (CollectionSerializer) cannot
213
+ identify a serializer for a resource in its collection, it throws [`:no_serializer`](https://github.com/rails-api/active_model_serializers/issues/1191#issuecomment-142327128).
214
+ For example, when caught by `Reflection#build_association`, and the association value is set directly:
831
215
 
832
216
  ```ruby
833
- class SomeController < ApplicationController
834
- serialization_scope :current_admin, except: [:index, :show]
835
- end
217
+ reflection_options[:virtual_value] = association_value.try(:as_json) || association_value
836
218
  ```
837
219
 
838
- So, in order to have a fine grained control of what each action should take in
839
- consideration for its scope, you may use something like this:
840
-
841
- ```ruby
842
- class CitiesController < ApplicationController
843
- serialization_scope nil
220
+ (which is called by the adapter as `serializer.associations(*)`.)
844
221
 
845
- def index
846
- @cities = City.all
222
+ ### How options are parsed
847
223
 
848
- render json: @cities, each_serializer: CitySerializer
849
- end
224
+ High-level overview:
850
225
 
851
- def show
852
- @city = City.find(params[:id])
226
+ - For a **collection**
227
+ - `:serializer` specifies the collection serializer and
228
+ - `:each_serializer` specifies the serializer for each resource in the collection.
229
+ - For a **single resource**, the `:serializer` option is the resource serializer.
230
+ - Options are partitioned in serializer options and adapter options. Keys for adapter options are specified by
231
+ [`ADAPTER_OPTION_KEYS`](lib/active_model_serializers/serializable_resource.rb#L5).
232
+ The remaining options are serializer options.
853
233
 
854
- render json: @city, scope: current_admin
855
- end
856
- end
857
- ```
234
+ Details:
858
235
 
859
- Assuming that the `current_admin` method needs to make a query in the database
860
- for the current user, the advantage of this approach is that, by setting
861
- `serialization_scope` to `nil`, the `index` action no longer will need to make
862
- that query, only the `show` action will.
236
+ 1. **ActionController::Serialization**
237
+ 1. `serializable_resource = ActiveModelSerializers::SerializableResource.new(resource, options)`
238
+ 1. `options` are partitioned into `adapter_opts` and everything else (`serializer_opts`).
239
+ The `adapter_opts` keys are defined in [`ActiveModelSerializers::SerializableResource::ADAPTER_OPTION_KEYS`](lib/active_model_serializers/serializable_resource.rb#L5).
240
+ 1. **ActiveModelSerializers::SerializableResource**
241
+ 1. `if serializable_resource.serializer?` (there is a serializer for the resource, and an adapter is used.)
242
+ - Where `serializer?` is `use_adapter? && !!(serializer)`
243
+ - Where `use_adapter?`: 'True when no explicit adapter given, or explicit value is truthy (non-nil);
244
+ False when explicit adapter is falsy (nil or false)'
245
+ - Where `serializer`:
246
+ 1. from explicit `:serializer` option, else
247
+ 2. implicitly from resource `ActiveModel::Serializer.serializer_for(resource)`
248
+ 1. A side-effect of checking `serializer` is:
249
+ - The `:serializer` option is removed from the serializer_opts hash
250
+ - If the `:each_serializer` option is present, it is removed from the serializer_opts hash and set as the `:serializer` option
251
+ 1. The serializer and adapter are created as
252
+ 1. `serializer_instance = serializer.new(resource, serializer_opts)`
253
+ 2. `adapter_instance = ActiveModel::Serializer::Adapter.create(serializer_instance, adapter_opts)`
254
+ 1. **ActiveModel::Serializer::CollectionSerializer#new**
255
+ 1. If the `serializer_instance` was a `CollectionSerializer` and the `:serializer` serializer_opts
256
+ is present, then [that serializer is passed into each resource](https://github.com/rails-api/active_model_serializers/blob/0-10-stable/lib/active_model/serializer/collection_serializer.rb#L77-L79).
257
+ 1. **ActiveModel::Serializer#attributes** is used by the adapter to get the attributes for
258
+ resource as defined by the serializer.
863
259
 
864
- ## Testing
260
+ (In Rails, the `options` are also passed to the `as_json(options)` or `to_json(options)`
261
+ methods on the resource serialization by the Rails JSON renderer. They are, therefore, important
262
+ to know about, but not part of ActiveModelSerializers.)
865
263
 
866
- In order to test a Serializer, you can just call `.new` on it, passing the object to serialize:
264
+ ### What does a 'serializable resource' look like?
867
265
 
868
- ### MiniTest
266
+ - An `ActiveRecord::Base` object.
267
+ - Any Ruby object that passes the
268
+ [Lint](https://www.rubydoc.info/gems/active_model_serializers/ActiveModel/Serializer/Lint/Tests)
269
+ [(code)](lib/active_model/serializer/lint.rb).
869
270
 
870
- ```ruby
871
- class TestPostSerializer < Minitest::Test
872
- def setup
873
- @serializer = PostSerializer.new Post.new(id: 123, title: 'some title', body: 'some text')
874
- end
875
-
876
- def test_special_json_for_api
877
- assert_equal '{"post":{"id":123,"title":"some title","body":"some text"}}', @serializer.to_json
878
- end
879
- ```
271
+ ActiveModelSerializers provides a
272
+ [`ActiveModelSerializers::Model`](lib/active_model_serializers/model.rb),
273
+ which is a simple serializable PORO (Plain-Old Ruby Object).
880
274
 
881
- ### RSpec
275
+ `ActiveModelSerializers::Model` may be used either as a reference implementation, or in production code.
882
276
 
883
277
  ```ruby
884
- describe PostSerializer do
885
- it "creates special JSON for the API" do
886
- serializer = PostSerializer.new Post.new(id: 123, title: 'some title', body: 'some text')
887
- expect(serializer.to_json).to eql('{"post":{"id":123,"title":"some title","body":"some text"}}')
888
- end
278
+ class MyModel < ActiveModelSerializers::Model
279
+ attributes :id, :name, :level
889
280
  end
890
281
  ```
891
282
 
892
- ## Caching
893
-
894
- NOTE: This functionality was removed from AMS and it's in the TODO list.
895
- We need to re-think and re-design the caching strategy for the next
896
- version of AMS.
283
+ The default serializer for `MyModel` would be `MyModelSerializer` whether MyModel is an
284
+ ActiveRecord::Base object or not.
897
285
 
898
- To cache a serializer, call `cached` and define a `cache_key` method:
286
+ Outside of the controller the rules are **exactly** the same as for records. For example:
899
287
 
900
288
  ```ruby
901
- class PostSerializer < ActiveModel::Serializer
902
- cached # enables caching for this serializer
903
-
904
- attributes :title, :body
905
-
906
- def cache_key
907
- [object, scope]
908
- end
909
- end
289
+ render json: MyModel.new(level: 'awesome'), adapter: :json
910
290
  ```
911
291
 
912
- The caching interface uses `Rails.cache` under the hood.
913
-
914
- # ApplicationSerializer
915
-
916
- By default, new serializers descend from ActiveModel::Serializer. However, if you wish to share behaviour across your serializers you can create an ApplicationSerializer at ```app/serializers/application_serializer.rb```:
292
+ would be serialized the same as
917
293
 
918
294
  ```ruby
919
- class ApplicationSerializer < ActiveModel::Serializer
920
- end
921
- ```
922
-
923
- Any newly generated serializers will automatically descend from ApplicationSerializer.
924
-
295
+ ActiveModelSerializers::SerializableResource.new(MyModel.new(level: 'awesome'), adapter: :json).as_json
925
296
  ```
926
- $ rails g serializer post
927
- ```
928
-
929
- now generates:
930
-
931
- ```ruby
932
- class PostSerializer < ApplicationSerializer
933
- attributes :id
934
- end
935
- ```
936
-
937
- # Design and Implementation Guidelines
938
297
 
939
- ## Keep it Simple
298
+ ## Semantic Versioning
940
299
 
941
- `ActiveModel::Serializers` is capable of producing complex JSON views/large object
942
- trees, and it may be tempting to design in this way so that your client can make
943
- fewer requests to get data and so that related querying can be optimized.
944
- However, keeping things simple in your serializers and controllers may
945
- significantly reduce complexity and maintenance over the long-term development
946
- of your application. Please consider reducing the complexity of the JSON views
947
- you provide via the serializers as you build out your application, so that
948
- controllers/services can be more easily reused without a lot of complexity
949
- later.
300
+ This project adheres to [semver](https://semver.org/)
950
301
 
951
- ## Performance
302
+ ## Contributing
952
303
 
953
- As you develop your controllers or other code that utilizes serializers, try to
954
- avoid n+1 queries by ensuring that data loads in an optimal fashion, e.g. if you
955
- are using ActiveRecord, you might want to use query includes or joins as needed
956
- to make the data available that the serializer(s) need.
304
+ See [CONTRIBUTING.md](CONTRIBUTING.md)