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