File: README.md

package info (click to toggle)
ruby-active-model-serializers 0.10.12-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,752 kB
  • sloc: ruby: 13,138; sh: 53; makefile: 6
file content (305 lines) | stat: -rw-r--r-- 12,858 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
# ActiveModelSerializers

<table>
  <tr>
    <td>Build Status</td>
    <td>
      <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>
      <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>
    </td>
  </tr>
  <tr>
    <td>Code Quality</td>
    <td>
      <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>
      <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>
      <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>
    </td>
  </tr>
  <tr>
    <td>Issue Stats</td>
    <td>
      <a href="https://github.com/rails-api/active_model_serializers/pulse/monthly">Pulse</a>
    </td>
  </tr>
</table>

## About

ActiveModelSerializers brings convention over configuration to your JSON generation.

ActiveModelSerializers works through two components: **serializers** and **adapters**.

Serializers describe _which_ attributes and relationships should be serialized.

Adapters describe _how_ attributes and relationships should be serialized.

SerializableResource co-ordinates the resource, Adapter and Serializer to produce the
resource serialization. The serialization has the `#as_json`, `#to_json` and `#serializable_hash`
methods used by the Rails JSON Renderer. (SerializableResource actually delegates
these methods to the adapter.)

By default ActiveModelSerializers will use the **Attributes Adapter** (no JSON root).
But we strongly advise you to use **JsonApi Adapter**, which
follows 1.0 of the format specified in [jsonapi.org/format](https://jsonapi.org/format).
Check how to change the adapter in the sections below.

`0.10.x` is **not** backward compatible with `0.9.x` nor `0.8.x`.

`0.10.x` is based on the `0.8.0` code, but with a more flexible
architecture. We'd love your help. [Learn how you can help here.](CONTRIBUTING.md)

## Installation

Add this line to your application's Gemfile:

```
gem 'active_model_serializers', '~> 0.10.0'
```

And then execute:

```
$ bundle
```

## Getting Started

See [Getting Started](docs/general/getting_started.md) for the nuts and bolts.

More information is available in the [Guides](docs) and
[High-level behavior](README.md#high-level-behavior).

## Getting Help

If you find a bug, please report an [Issue](https://github.com/rails-api/active_model_serializers/issues/new)
and see our [contributing guide](CONTRIBUTING.md).

If you have a question, please [post to Stack Overflow](https://stackoverflow.com/questions/tagged/active-model-serializers).

If you'd like to chat, we have a [community slack](https://amserializers.herokuapp.com).

Thanks!

## Documentation

If you're reading this at https://github.com/rails-api/active_model_serializers you are
reading documentation for our `master`, which may include features that have not
been released yet. Please see below for the documentation relevant to you.

- [0.10 (0-10-stable) Documentation](https://github.com/rails-api/active_model_serializers/tree/0-10-stable)
- [0.10.10 (latest release) Documentation](https://github.com/rails-api/active_model_serializers/tree/v0.10.10)
    - [![API Docs](https://img.shields.io/badge/yard-docs-blue.svg)](https://www.rubydoc.info/gems/active_model_serializers/0.10.10)
    - [Guides](docs)
- [0.9 (0-9-stable) Documentation](https://github.com/rails-api/active_model_serializers/tree/0-9-stable)
    - [![API Docs](https://img.shields.io/badge/yard-docs-blue.svg)](https://www.rubydoc.info/gems/active_model_serializers/0.9.7)
- [0.8 (0-8-stable) Documentation](https://github.com/rails-api/active_model_serializers/tree/0-8-stable)
    - [![API Docs](https://img.shields.io/badge/yard-docs-blue.svg)](https://www.rubydoc.info/gems/active_model_serializers/0.8.4)


## High-level behavior

Choose an adapter from [adapters](lib/active_model_serializers/adapter):

``` ruby
ActiveModelSerializers.config.adapter = :json_api # Default: `:attributes`
```

Given a [serializable model](lib/active_model/serializer/lint.rb):

```ruby
# either
class SomeResource < ActiveRecord::Base
  # columns: title, body
end
# or
class SomeResource < ActiveModelSerializers::Model
  attributes :title, :body
end
```

And initialized as:

```ruby
resource = SomeResource.new(title: 'ActiveModelSerializers', body: 'Convention over configuration')
```

Given a serializer for the serializable model:

```ruby
class SomeSerializer < ActiveModel::Serializer
  attribute :title, key: :name
  attributes :body
end
```

The model can be serialized as:

```ruby
options = {}
serialization = ActiveModelSerializers::SerializableResource.new(resource, options)
serialization.to_json
serialization.as_json
```

SerializableResource delegates to the adapter, which it builds as:

```ruby
adapter_options = {}
adapter = ActiveModelSerializers::Adapter.create(serializer, adapter_options)
adapter.to_json
adapter.as_json
adapter.serializable_hash
```

The adapter formats the serializer's attributes and associations (a.k.a. includes):

```ruby
serializer_options = {}
serializer = SomeSerializer.new(resource, serializer_options)
serializer.attributes
serializer.associations
```

## Architecture

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,
please refer to the [0.8 README](https://github.com/rails-api/active_model_serializers/blob/0-8-stable/README.md) or
[0.9 README](https://github.com/rails-api/active_model_serializers/blob/0-9-stable/README.md).

The original design is also available [here](https://github.com/rails-api/active_model_serializers/blob/d72b66d4c5355b0ff0a75a04895fcc4ea5b0c65e/README.textile).

### ActiveModel::Serializer

An **`ActiveModel::Serializer`** wraps a [serializable resource](https://github.com/rails/rails/blob/master/activemodel/lib/active_model/serialization.rb)
and exposes an `attributes` method, among a few others.
It allows you to specify which attributes and associations should be represented in the serializatation of the resource.
It requires an adapter to transform its attributes into a JSON document; it cannot be serialized itself.
It may be useful to think of it as a
[presenter](https://blog.steveklabnik.com/posts/2011-09-09-better-ruby-presenters).

#### ActiveModel::CollectionSerializer

The **`ActiveModel::CollectionSerializer`** represents a collection of resources as serializers
and, if there is no serializer, primitives.

### ActiveModelSerializers::Adapter::Base

The **`ActiveModelSerializers::Adapter::Base`** describes the structure of the JSON document generated from a
serializer. For example, the `Attributes` example represents each serializer as its
unmodified attributes.  The `JsonApi` adapter represents the serializer as a [JSON
API](https://jsonapi.org/) document.

### ActiveModelSerializers::SerializableResource

The **`ActiveModelSerializers::SerializableResource`** acts to coordinate the serializer(s) and adapter
to an object that responds to `to_json`, and `as_json`.  It is used in the controller to
encapsulate the serialization resource when rendered. However, it can also be used on its own
to serialize a resource outside of a controller, as well.

### Primitive handling

Definitions: A primitive is usually a String or Array. There is no serializer
defined for them; they will be serialized when the resource is converted to JSON (`as_json` or
`to_json`).  (The below also applies for any object with no serializer.)

- ActiveModelSerializers doesn't handle primitives passed to `render json:` at all.

Internally, if no serializer can be found in the controller, the resource is not decorated by
ActiveModelSerializers.

- However, when a primitive value is an attribute or in a collection, it is not modified.

When serializing a collection and the collection serializer (CollectionSerializer) cannot
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).
For example, when caught by `Reflection#build_association`, and the association value is set directly:

```ruby
reflection_options[:virtual_value] = association_value.try(:as_json) || association_value
```

(which is called by the adapter as `serializer.associations(*)`.)

### How options are parsed

High-level overview:

- For a **collection**
  - `:serializer` specifies the collection serializer and
  - `:each_serializer` specifies the serializer for each resource in the collection.
- For a **single resource**, the `:serializer` option is the resource serializer.
- Options are partitioned in serializer options and adapter options.  Keys for adapter options are specified by
    [`ADAPTER_OPTION_KEYS`](lib/active_model_serializers/serializable_resource.rb#L5).
    The remaining options are serializer options.

Details:

1. **ActionController::Serialization**
  1. `serializable_resource = ActiveModelSerializers::SerializableResource.new(resource, options)`
    1. `options` are partitioned into `adapter_opts` and everything else (`serializer_opts`).
      The `adapter_opts` keys are defined in [`ActiveModelSerializers::SerializableResource::ADAPTER_OPTION_KEYS`](lib/active_model_serializers/serializable_resource.rb#L5).
1. **ActiveModelSerializers::SerializableResource**
  1. `if serializable_resource.serializer?` (there is a serializer for the resource, and an adapter is used.)
    - Where `serializer?` is `use_adapter? && !!(serializer)`
      - Where `use_adapter?`: 'True when no explicit adapter given, or explicit value is truthy (non-nil);
        False when explicit adapter is falsy (nil or false)'
      - Where `serializer`:
        1. from explicit `:serializer` option, else
        2. implicitly from resource `ActiveModel::Serializer.serializer_for(resource)`
  1. A side-effect of checking `serializer` is:
     - The `:serializer` option is removed from the serializer_opts hash
     - If the `:each_serializer` option is present, it is removed from the serializer_opts hash and set as the `:serializer` option
  1. The serializer and adapter are created as
    1. `serializer_instance = serializer.new(resource, serializer_opts)`
    2. `adapter_instance = ActiveModel::Serializer::Adapter.create(serializer_instance, adapter_opts)`
1. **ActiveModel::Serializer::CollectionSerializer#new**
  1. If the `serializer_instance` was a `CollectionSerializer` and the `:serializer` serializer_opts
    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).
1. **ActiveModel::Serializer#attributes** is used by the adapter to get the attributes for
  resource as defined by the serializer.

(In Rails, the `options` are also passed to the `as_json(options)` or `to_json(options)`
methods on the resource serialization by the Rails JSON renderer.  They are, therefore, important
to know about, but not part of ActiveModelSerializers.)

### What does a 'serializable resource' look like?

- An `ActiveRecord::Base` object.
- Any Ruby object that passes the
  [Lint](https://www.rubydoc.info/gems/active_model_serializers/ActiveModel/Serializer/Lint/Tests)
  [(code)](lib/active_model/serializer/lint.rb).

ActiveModelSerializers provides a
[`ActiveModelSerializers::Model`](lib/active_model_serializers/model.rb),
which is a simple serializable PORO (Plain-Old Ruby Object).

`ActiveModelSerializers::Model` may be used either as a reference implementation, or in production code.

```ruby
class MyModel < ActiveModelSerializers::Model
  attributes :id, :name, :level
end
```

The default serializer for `MyModel` would be `MyModelSerializer` whether MyModel is an
ActiveRecord::Base object or not.

Outside of the controller the rules are **exactly** the same as for records. For example:

```ruby
render json: MyModel.new(level: 'awesome'), adapter: :json
```

would be serialized the same as

```ruby
ActiveModelSerializers::SerializableResource.new(MyModel.new(level: 'awesome'), adapter: :json).as_json
```

## Semantic Versioning

This project adheres to [semver](https://semver.org/)

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md)