Adapters
ActiveModelSerializers offers the ability to configure which adapter to use both globally and/or when serializing (usually when rendering).
The global adapter configuration is set on ActiveModelSerializers.config. It should be set only once, preferably at initialization.
For example:
ActiveModelSerializers.config.adapter = ActiveModelSerializers::Adapter::JsonApi
or
ActiveModelSerializers.config.adapter = :json_api
or
ActiveModelSerializers.config.adapter = :json
The local adapter option is in the format adapter: adapter
,
where adapter
is any of the same values as set globally.
The configured adapter can be set as a symbol, class, or class name, as described in Advanced adapter configuration.
The Attributes
adapter does not include a root key. It is just
the serialized attributes.
Use either the JSON
or JSON API
adapters if you
want the response document to have a root key.
Built in Adapters
Attributes - Default
It's the default adapter, it generates a json response without a root key. Doesn't follow any specific convention.
Example output
{
"title": "Title 1",
"body": "Body 1",
"publish_at": "2020-03-16T03:55:25.291Z",
"author": {
"first_name": "Bob",
"last_name": "Jones"
},
"comments": [
{
"body": "cool"
},
{
"body": "awesome"
}
]
}
JSON
The json response is always rendered with a root key.
The root key can be overridden by: * passing the root
option
in the render call. See details in the Rendering Guides. * setting
the type
of the serializer. See details in the Serializers Guide.
Doesn't follow any specific convention.
Example output
{
"post": {
"title": "Title 1",
"body": "Body 1",
"publish_at": "2020-03-16T03:55:25.291Z",
"author": {
"first_name": "Bob",
"last_name": "Jones"
},
"comments": [{
"body": "cool"
}, {
"body": "awesome"
}]
}
}
JSON API
This adapter follows version 1.0 of the format specified in jsonapi.org/format.
Example output
{
"data": {
"id": "1337",
"type": "posts",
"attributes": {
"title": "Title 1",
"body": "Body 1",
"publish-at": "2020-03-16T03:55:25.291Z"
},
"relationships": {
"author": {
"data": {
"id": "1",
"type": "authors"
}
},
"comments": {
"data": [{
"id": "7",
"type": "comments"
}, {
"id": "12",
"type": "comments"
}]
}
},
"links": {
"post-authors": "https://example.com/post_authors"
},
"meta": {
"rating": 5,
"favorite-count": 10
}
}
}
Included
It will include the associated resources in the
"included"
member when the resource names are
included in the include
option. Including nested associated
resources is also supported.
render json: @posts, include: ['author', 'comments', 'comments.author']
# or
render json: @posts, include: 'author,comments,comments.author'
In addition, two types of wildcards may be used:
-
*
includes one level of associations. -
**
includes all recursively.
These can be combined with other paths.
render json: @posts, include: '**' # or '*' for a single layer
The format of the include
option can be either:
-
a String composed of a comma-separated list of relationship paths.
-
an Array of Symbols and Hashes.
-
a mix of both.
The following would render posts and include:
-
the author
-
the author's comments, and
-
every resource referenced by the author's comments (recursively).
It could be combined, like above, with other paths in any combination desired.
render json: @posts, include: 'author.comments.**'
Security Considerations
Since the included options may come from the query params (i.e. user-controller):
render json: @posts, include: params[:include]
The user could pass in include=**
.
We recommend filtering any user-supplied includes appropriately.
Advanced adapter configuration
Registering an adapter
The default adapter can be configured, as above, to use any class given to it.
An adapter may also be specified, e.g. when rendering, as a class or as a
symbol. If a symbol, then the adapter must be, e.g.
:great_example
,
ActiveModelSerializers::Adapter::GreatExample
, or registered.
There are two ways to register an adapter:
1) The simplest, is to subclass
ActiveModelSerializers::Adapter::Base
, e.g. the below will
register the Example::UsefulAdapter
as
"example/useful_adapter"
.
module Example
class UsefulAdapter < ActiveModelSerializers::Adapter::Base
end
end
You'll notice that the name it registers is the underscored namespace and class.
Under the covers, when the
ActiveModelSerializers::Adapter::Base
is subclassed, it
registers the subclass as
register("example/useful_adapter",
Example::UsefulAdapter)
2) Any class can be registered as an adapter by calling
register
directly on the
ActiveModelSerializers::Adapter
class. e.g., the below
registers MyAdapter
as :special_adapter
.
class MyAdapter; end
ActiveModelSerializers::Adapter.register(:special_adapter, MyAdapter)
Looking up an adapter
| Method | Return value | | :———— |:—————| |
ActiveModelSerializers::Adapter.adapter_map
| A Hash of all
known adapters { adapter_name => adapter_class }
| |
ActiveModelSerializers::Adapter.adapters
| A (sorted) Array of
all known adapter_names
| |
ActiveModelSerializers::Adapter.lookup(name_or_klass)
| The
adapter_class
, else raises an
ActiveModelSerializers::Adapter::UnknownAdapter
error | |
ActiveModelSerializers::Adapter.adapter_class(adapter)
|
Delegates to ActiveModelSerializers::Adapter.lookup(adapter)
|
| ActiveModelSerializers::Adapter.configured_adapter
| A
convenience method for
ActiveModelSerializers::Adapter.lookup(config.adapter)
|
The registered adapter name is always a String, but may be looked up as a
Symbol or String. Helpfully, the Symbol or String is underscored, so that
get(:my_adapter)
and get("MyAdapter")
may both be used.
For more information, see the Adapter class on GitHub