Guides > Architecture
Architecture
This focuses on 0.10.x version. For the architectures of 0.8 or 0.9 versions, please refer to 0.8 README or 0.9 README. The original design is also available here.
ActiveModel::Serializer
- Wraps a serializable resource and exposes an
attributesmethod, among a few others - Allows specifying which attributes and associations should be represented in the serializatation of the resource
- Requires an adapter to transform its attributes into a JSON document; it cannot be serialized itself
- Think of it as a case-specific presenter
ActiveModel::ArraySerializer
A collection of resources as serializers or as primitives if there are no serializers
ActiveModel::Adapter
Defines the structure of the JSON document to be generated from a serializer. For example:
AttributesAdapter represents each serializer as its unmodified attributesJsonApiAdapter represents the serializer as a JSON API document
ActiveModelSerializers::SerializableResource
- Acts to coordinate the serializer(s) and adapter to an object that responds to
to_json, andas_json - Used in the controller to encapsulate the serialization resource when rendered
- Can be used on its own to serialize a resource outside of a controller
- Characteristics
ActiveModelSerializers::Model
ActiveModelSerializers provides a ActiveModelSerializers::Model as a simple serializable PORO (Plain-Old Ruby Object) that can be used either as a template, or in production code:
class MyModel < ActiveModelSerializers::Model
attr_accessor :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:
render json: MyModel.new(level: 'awesome'), adapter: :json
is equivelant to
ActiveModelSerializers::SerializableResource.new(MyModel.new(level: 'awesome'), adapter: :json).as_json
Primitive Handling
- 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_jsonorto_json). (The below also applies for any object with no serializer.) ActiveModelSerializersdoesn't handle primitives passed torender json:at all. When a primitive value is an attribute or in a collection, it is not modified.- Internally, if no serializer can be found in the controller, the resource is not decorated by ActiveModelSerializers.
- If the collection serializer (
ArraySerializer) cannot identify a serializer for a resource in its collection, it raisesNoSerializerErrorwhich is rescued inAcitveModel::Serializer::Reflection#build_associationwhich sets the association value directly:which is called by the adapter asreflection_options[:virtual_value] = association_value.try(:as_json) || association_valueserializer.associations(*).
Parsing Options
Summary
- For a single resource the
:serializeroption is the resource serializer - For a collection
:serializerspecifies the collection serializer:each_serializerspecifies the serializer for each resource in the collection.
- Options are partitioned in Serializer Options and Adapter Options
- Keys for Adapter Options are specified by
ADAPTER_OPTION_KEYS- The remaining options are serializer options
Details
ActionController::Serialization
serializable_resource = ActiveModelSerializers::SerializableResource.new(resource, options)optionsare partitioned intoadapter_optsand everything else (serializer_opts).- The
adapter_optskeys are defined inActiveModelSerializers::SerializableResource::ADAPTER_OPTION_KEYS.
ActiveModelSerializers::SerializableResource
if serializable_resource.serializer?(there is a serializer for the resource, and an adapter is used.)- Where
serializer?isuse_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:from explicit
:serializeroption, else- implicitly from resource
ActiveModel::Serializer.serializer_for(resource)
- Where
A side-effect of checking
serializeris:- The
:serializeroption is removed from the serializer_opts hash - If the
:each_serializeroption is present, it is removed from the serializer_opts hash and set as the:serializeroption
- The
The serializer and adapter are created as
serializer_instance = serializer.new(resource, serializer_opts)adapter_instance = ActiveModel::Serializer::Adapter.create(serializer_instance, adapter_opts)
ActiveModel::Serializer::ArraySerializer#new
- If the
serializer_instancewas aArraySerializerand the:serializerserializer_opts - is present, then that serializer is passed into each resource.
- If the
ActiveModel::Serializer#attributes is used by the adapter to get the attributes for
- Resource as defined by the serializer.