active_model_serializers 0.9.12 → 0.10.15

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 (142) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +638 -82
  3. data/MIT-LICENSE +3 -2
  4. data/README.md +194 -846
  5. data/lib/action_controller/serialization.rb +34 -74
  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 +53 -38
  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 +1 -1
  31. data/lib/active_model/serializer.rb +361 -263
  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 +62 -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 +58 -27
  61. data/lib/generators/rails/USAGE +6 -0
  62. data/lib/{active_model/serializer/generators → generators/rails}/resource_override.rb +1 -4
  63. data/lib/{active_model/serializer/generators/serializer → generators/rails}/serializer_generator.rb +4 -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 -82
  72. data/lib/active_model/array_serializer.rb +0 -70
  73. data/lib/active_model/default_serializer.rb +0 -30
  74. data/lib/active_model/serializable/utils.rb +0 -18
  75. data/lib/active_model/serializable.rb +0 -61
  76. data/lib/active_model/serializer/association/has_many.rb +0 -41
  77. data/lib/active_model/serializer/association/has_one.rb +0 -27
  78. data/lib/active_model/serializer/config.rb +0 -33
  79. data/lib/active_model/serializer/generators/serializer/USAGE +0 -9
  80. data/lib/active_model/serializer/generators/serializer/scaffold_controller_generator.rb +0 -16
  81. data/lib/active_model/serializer/generators/serializer/templates/controller.rb +0 -93
  82. data/lib/active_model/serializer/railtie.rb +0 -24
  83. data/lib/active_model/serializer_support.rb +0 -7
  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 -255
  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 -18
  109. data/test/test_helper.rb +0 -31
  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 -36
  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)