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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +638 -82
- data/MIT-LICENSE +3 -2
- data/README.md +194 -846
- data/lib/action_controller/serialization.rb +34 -74
- data/lib/active_model/serializable_resource.rb +13 -0
- data/lib/active_model/serializer/adapter/attributes.rb +17 -0
- data/lib/active_model/serializer/adapter/base.rb +20 -0
- data/lib/active_model/serializer/adapter/json.rb +17 -0
- data/lib/active_model/serializer/adapter/json_api.rb +17 -0
- data/lib/active_model/serializer/adapter/null.rb +17 -0
- data/lib/active_model/serializer/adapter.rb +26 -0
- data/lib/active_model/serializer/array_serializer.rb +14 -0
- data/lib/active_model/serializer/association.rb +53 -38
- data/lib/active_model/serializer/attribute.rb +27 -0
- data/lib/active_model/serializer/belongs_to_reflection.rb +13 -0
- data/lib/active_model/serializer/collection_serializer.rb +99 -0
- data/lib/active_model/serializer/concerns/caching.rb +305 -0
- data/lib/active_model/serializer/error_serializer.rb +16 -0
- data/lib/active_model/serializer/errors_serializer.rb +34 -0
- data/lib/active_model/serializer/field.rb +92 -0
- data/lib/active_model/serializer/fieldset.rb +33 -0
- data/lib/active_model/serializer/has_many_reflection.rb +12 -0
- data/lib/active_model/serializer/has_one_reflection.rb +9 -0
- data/lib/active_model/serializer/lazy_association.rb +99 -0
- data/lib/active_model/serializer/link.rb +23 -0
- data/lib/active_model/serializer/lint.rb +152 -0
- data/lib/active_model/serializer/null.rb +19 -0
- data/lib/active_model/serializer/reflection.rb +212 -0
- data/lib/active_model/serializer/version.rb +1 -1
- data/lib/active_model/serializer.rb +361 -263
- data/lib/active_model_serializers/adapter/attributes.rb +36 -0
- data/lib/active_model_serializers/adapter/base.rb +85 -0
- data/lib/active_model_serializers/adapter/json.rb +23 -0
- data/lib/active_model_serializers/adapter/json_api/deserialization.rb +215 -0
- data/lib/active_model_serializers/adapter/json_api/error.rb +98 -0
- data/lib/active_model_serializers/adapter/json_api/jsonapi.rb +51 -0
- data/lib/active_model_serializers/adapter/json_api/link.rb +85 -0
- data/lib/active_model_serializers/adapter/json_api/meta.rb +39 -0
- data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +94 -0
- data/lib/active_model_serializers/adapter/json_api/relationship.rb +106 -0
- data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +68 -0
- data/lib/active_model_serializers/adapter/json_api.rb +535 -0
- data/lib/active_model_serializers/adapter/null.rb +11 -0
- data/lib/active_model_serializers/adapter.rb +100 -0
- data/lib/active_model_serializers/callbacks.rb +57 -0
- data/lib/active_model_serializers/deprecate.rb +56 -0
- data/lib/active_model_serializers/deserialization.rb +17 -0
- data/lib/active_model_serializers/json_pointer.rb +16 -0
- data/lib/active_model_serializers/logging.rb +124 -0
- data/lib/active_model_serializers/lookup_chain.rb +82 -0
- data/lib/active_model_serializers/model.rb +132 -0
- data/lib/active_model_serializers/railtie.rb +62 -0
- data/lib/active_model_serializers/register_jsonapi_renderer.rb +80 -0
- data/lib/active_model_serializers/serializable_resource.rb +84 -0
- data/lib/active_model_serializers/serialization_context.rb +41 -0
- data/lib/active_model_serializers/test/schema.rb +140 -0
- data/lib/active_model_serializers/test/serializer.rb +127 -0
- data/lib/active_model_serializers/test.rb +9 -0
- data/lib/active_model_serializers.rb +58 -27
- data/lib/generators/rails/USAGE +6 -0
- data/lib/{active_model/serializer/generators → generators/rails}/resource_override.rb +1 -4
- data/lib/{active_model/serializer/generators/serializer → generators/rails}/serializer_generator.rb +4 -5
- data/lib/grape/active_model_serializers.rb +18 -0
- data/lib/grape/formatters/active_model_serializers.rb +34 -0
- data/lib/grape/helpers/active_model_serializers.rb +19 -0
- data/lib/tasks/rubocop.rake +60 -0
- metadata +248 -155
- data/CONTRIBUTING.md +0 -20
- data/DESIGN.textile +0 -586
- data/lib/action_controller/serialization_test_case.rb +0 -82
- data/lib/active_model/array_serializer.rb +0 -70
- data/lib/active_model/default_serializer.rb +0 -30
- data/lib/active_model/serializable/utils.rb +0 -18
- data/lib/active_model/serializable.rb +0 -61
- data/lib/active_model/serializer/association/has_many.rb +0 -41
- data/lib/active_model/serializer/association/has_one.rb +0 -27
- data/lib/active_model/serializer/config.rb +0 -33
- data/lib/active_model/serializer/generators/serializer/USAGE +0 -9
- data/lib/active_model/serializer/generators/serializer/scaffold_controller_generator.rb +0 -16
- data/lib/active_model/serializer/generators/serializer/templates/controller.rb +0 -93
- data/lib/active_model/serializer/railtie.rb +0 -24
- data/lib/active_model/serializer_support.rb +0 -7
- data/test/benchmark/app.rb +0 -60
- data/test/benchmark/benchmarking_support.rb +0 -67
- data/test/benchmark/bm_active_record.rb +0 -41
- data/test/benchmark/setup.rb +0 -75
- data/test/benchmark/tmp/miniprofiler/mp_timers_6eqewtfgrhitvq5gqm25 +0 -0
- data/test/benchmark/tmp/miniprofiler/mp_timers_8083sx03hu72pxz1a4d0 +0 -0
- data/test/benchmark/tmp/miniprofiler/mp_timers_fyz2gsml4z0ph9kpoy1c +0 -0
- data/test/benchmark/tmp/miniprofiler/mp_timers_hjry5rc32imd42oxoi48 +0 -0
- data/test/benchmark/tmp/miniprofiler/mp_timers_m8fpoz2cvt3g9agz0bs3 +0 -0
- data/test/benchmark/tmp/miniprofiler/mp_timers_p92m2drnj1i568u3sta0 +0 -0
- data/test/benchmark/tmp/miniprofiler/mp_timers_qg52tpca3uesdfguee9i +0 -0
- data/test/benchmark/tmp/miniprofiler/mp_timers_s15t1a6mvxe0z7vjv790 +0 -0
- data/test/benchmark/tmp/miniprofiler/mp_timers_x8kal3d17nfds6vp4kcj +0 -0
- data/test/benchmark/tmp/miniprofiler/mp_views_127.0.0.1 +0 -0
- data/test/fixtures/active_record.rb +0 -96
- data/test/fixtures/poro.rb +0 -255
- data/test/fixtures/template.html.erb +0 -1
- data/test/integration/action_controller/namespaced_serialization_test.rb +0 -105
- data/test/integration/action_controller/serialization_test.rb +0 -287
- data/test/integration/action_controller/serialization_test_case_test.rb +0 -71
- data/test/integration/active_record/active_record_test.rb +0 -94
- data/test/integration/generators/resource_generator_test.rb +0 -26
- data/test/integration/generators/scaffold_controller_generator_test.rb +0 -64
- data/test/integration/generators/serializer_generator_test.rb +0 -41
- data/test/test_app.rb +0 -18
- data/test/test_helper.rb +0 -31
- data/test/tmp/app/assets/javascripts/accounts.js +0 -2
- data/test/tmp/app/assets/stylesheets/accounts.css +0 -4
- data/test/tmp/app/controllers/accounts_controller.rb +0 -3
- data/test/tmp/app/helpers/accounts_helper.rb +0 -3
- data/test/tmp/app/serializers/account_serializer.rb +0 -4
- data/test/tmp/config/routes.rb +0 -2
- data/test/unit/active_model/array_serializer/except_test.rb +0 -18
- data/test/unit/active_model/array_serializer/key_format_test.rb +0 -18
- data/test/unit/active_model/array_serializer/meta_test.rb +0 -53
- data/test/unit/active_model/array_serializer/only_test.rb +0 -18
- data/test/unit/active_model/array_serializer/options_test.rb +0 -16
- data/test/unit/active_model/array_serializer/root_test.rb +0 -102
- data/test/unit/active_model/array_serializer/scope_test.rb +0 -24
- data/test/unit/active_model/array_serializer/serialization_test.rb +0 -239
- data/test/unit/active_model/default_serializer_test.rb +0 -13
- data/test/unit/active_model/serializer/associations/build_serializer_test.rb +0 -36
- data/test/unit/active_model/serializer/associations_test.rb +0 -49
- data/test/unit/active_model/serializer/attributes_test.rb +0 -57
- data/test/unit/active_model/serializer/config_test.rb +0 -91
- data/test/unit/active_model/serializer/filter_test.rb +0 -69
- data/test/unit/active_model/serializer/has_many_polymorphic_test.rb +0 -189
- data/test/unit/active_model/serializer/has_many_test.rb +0 -265
- data/test/unit/active_model/serializer/has_one_and_has_many_test.rb +0 -27
- data/test/unit/active_model/serializer/has_one_polymorphic_test.rb +0 -196
- data/test/unit/active_model/serializer/has_one_test.rb +0 -253
- data/test/unit/active_model/serializer/key_format_test.rb +0 -25
- data/test/unit/active_model/serializer/meta_test.rb +0 -39
- data/test/unit/active_model/serializer/options_test.rb +0 -42
- data/test/unit/active_model/serializer/root_test.rb +0 -117
- data/test/unit/active_model/serializer/scope_test.rb +0 -49
- data/test/unit/active_model/serializer/url_helpers_test.rb +0 -36
- data/test/unit/active_model/serilizable_test.rb +0 -50
- /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
|
-
|
2
|
-
[](https://codeclimate.com/github/rails-api/active_model_serializers)
|
1
|
+
# ActiveModelSerializers
|
3
2
|
|
4
|
-
|
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
|
-
##
|
26
|
+
## About
|
7
27
|
|
8
|
-
|
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
|
-
|
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
|
-
|
17
|
-
development.**
|
32
|
+
Serializers describe _which_ attributes and relationships should be serialized.
|
18
33
|
|
19
|
-
|
34
|
+
Adapters describe _how_ attributes and relationships should be serialized.
|
20
35
|
|
21
|
-
|
22
|
-
`
|
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
|
-
|
25
|
-
|
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
|
-
|
46
|
+
`0.10.x` is **not** backward compatible with `0.9.x` nor `0.8.x`.
|
280
47
|
|
281
|
-
|
282
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
360
|
-
option:
|
65
|
+
## Getting Started
|
361
66
|
|
362
|
-
|
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
|
-
|
69
|
+
More information is available in the [Guides](docs) and
|
70
|
+
[High-level behavior](README.md#high-level-behavior).
|
367
71
|
|
368
|
-
|
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
|
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
|
-
|
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
|
-
|
79
|
+
If you'd like to chat, we have a [community slack](https://amserializers.herokuapp.com).
|
385
80
|
|
386
|
-
|
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
|
-
|
397
|
-
invalid JSON. If you do not have a root key, the meta information will be ignored.
|
83
|
+
## Documentation
|
398
84
|
|
399
|
-
If you
|
400
|
-
|
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
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
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
|
+
- [](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
|
+
- [](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
|
+
- [](https://www.rubydoc.info/gems/active_model_serializers/0.8.4)
|
416
97
|
|
417
|
-
## Associations
|
418
98
|
|
419
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
442
|
-
use for a particular association.
|
107
|
+
Given a [serializable model](lib/active_model/serializer/lint.rb):
|
443
108
|
|
444
109
|
```ruby
|
445
|
-
|
446
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
604
|
-
|
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
|
-
|
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
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
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
|
-
|
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
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
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
|
-
|
703
|
-
objects:
|
154
|
+
The adapter formats the serializer's attributes and associations (a.k.a. includes):
|
704
155
|
|
705
156
|
```ruby
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
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
|
-
|
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
|
-
|
731
|
-
|
732
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
180
|
+
#### ActiveModel::CollectionSerializer
|
742
181
|
|
743
|
-
|
182
|
+
The **`ActiveModel::CollectionSerializer`** represents a collection of resources as serializers
|
183
|
+
and, if there is no serializer, primitives.
|
744
184
|
|
745
|
-
|
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
|
-
|
786
|
-
|
787
|
-
|
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
|
-
|
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
|
-
|
199
|
+
### Primitive handling
|
811
200
|
|
812
|
-
|
813
|
-
|
814
|
-
`
|
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
|
-
|
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
|
-
|
824
|
-
|
207
|
+
Internally, if no serializer can be found in the controller, the resource is not decorated by
|
208
|
+
ActiveModelSerializers.
|
825
209
|
|
826
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
846
|
-
@cities = City.all
|
222
|
+
### How options are parsed
|
847
223
|
|
848
|
-
|
849
|
-
end
|
224
|
+
High-level overview:
|
850
225
|
|
851
|
-
|
852
|
-
|
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
|
-
|
855
|
-
end
|
856
|
-
end
|
857
|
-
```
|
234
|
+
Details:
|
858
235
|
|
859
|
-
|
860
|
-
|
861
|
-
`
|
862
|
-
|
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
|
-
|
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
|
-
|
264
|
+
### What does a 'serializable resource' look like?
|
867
265
|
|
868
|
-
|
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
|
-
|
871
|
-
|
872
|
-
|
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
|
-
|
275
|
+
`ActiveModelSerializers::Model` may be used either as a reference implementation, or in production code.
|
882
276
|
|
883
277
|
```ruby
|
884
|
-
|
885
|
-
|
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
|
-
|
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
|
-
|
286
|
+
Outside of the controller the rules are **exactly** the same as for records. For example:
|
899
287
|
|
900
288
|
```ruby
|
901
|
-
|
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
|
-
|
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
|
-
|
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
|
-
##
|
298
|
+
## Semantic Versioning
|
940
299
|
|
941
|
-
|
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
|
-
##
|
302
|
+
## Contributing
|
952
303
|
|
953
|
-
|
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)
|