LoginSignup
98
79

More than 3 years have passed since last update.

gem Active Model Serializers のドキュメントを翻訳しました

Last updated at Posted at 2020-03-17

概要

gem active_model_serializers の version 0-10-stable のドキュメントを翻訳しました。
Rails で API を作成するときに active_model_serializers を使うことも多いと思うので、参考になれば幸いです。

目次

Adapters

ActiveModelSerializers は、グローバルに、またはシリアライズするとき(通常はレンダリング時)に、どのアダプタを使用するかを設定する機能を提供します。

グローバルなアダプタ設定は ActiveModelSerializers.config で設定されます。
できれば初期化時に一度だけ設定することが望ましいです。

ActiveModelSerializers.config.adapter = ActiveModelSerializers::Adapter::JsonApi
ActiveModelSerializers.config.adapter = :json_api
ActiveModelSerializers.config.adapter = :json

ローカルのアダプタのオプションは adapter: adapter の形式で記載されます。adapter にはグローバル設定と同じ値が入ります。

Advanced adapter configuration に記載されているように、設定されたアダプタは、シンボル、クラス、またはクラス名として設定できます。

Attributes アダプタにはルートキーは含まれず、単純にシリアライズされた属性となります。

レスポンスドキュメントにルートキーを含めたい場合は、JSON または JSON API アダプタを使用してください。

重要: アダプタ設定は直接使用されるシリアライザのインスタンスには効果がありません。つまり、 UserSerializer.new(user).as_jsonAttributes アダプタのように振る舞います。推奨する使用方法の詳細については Outside Controller Usage をご覧ください。

Built in Adapters

Attributes(デフォルト)

デフォルトのアダプタで、ルートキーなしで json レスポンスを生成します。特定の規則には従っていません。

出力例

{
  "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

json レスポンスは常にルートキーを伴ってレンダリングされます。

ルートキーは下記の方法で上書きできます。
* render を呼び出すときに root オプションを渡す方法。詳細は Rendering Guides をご覧ください。
* シリアライザの type を設定する方法。詳細は Serializers Guide をご覧ください。

特定の規則には従っていません。

出力例

{
  "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

このアダプタは jsonapi.org/format における指定フォーマットversion 1.0 に従います。

出力例

{
  "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
    }
  }
}

Include オプション

どのシリアライザの関連付けがレンダリングされるかは include オプションを使用して指定できます。include オプションの使用方法は JSON API 仕様の include オプションと同じであり、すべてのアダプタで利用できます。

使用例

  render json: @posts, include: ['author', 'comments', 'comments.author']
  # or
  render json: @posts, include: 'author,comments,comments.author'

include オプションの形式は下記のいずれかです。

  • リレーションパスのカンマ区切りのリストで構成される文字列
  • シンボルとハッシュの配列
  • その2つの組み合わせ

空の文字列または空の配列は、関連付けのレンダリングを防ぎます。

さらに、2種類のワイルドカードを使用できます。

  • * は1レベルの関連付けを含みます。
  • ** すべての関連付けを再帰的に含みます。

ワイルドカードは他のパスと組み合わせることができます。

  render json: @posts, include: '**' # or '*' for a single layer

下記はポストをレンダリングして 次のリソースを include しています。

  • author
  • author の comments
  • author の comments によって参照されるすべてのリソース(再帰的)

上記のように、任意の組み合わせで他のパスと組み合わせることができます。

  render json: @posts, include: 'author.comments.**'

注意: ワイルドカードは ActiveModelSerializer 固有のものであり、JSON API 仕様の一部ではありません。

JSON API アダプタのデフォルトの include は、関連付けの設定がありません。 JSON および Attributes アダプタのデフォルトは、すべての関連付けが設定されています。

JSON API アダプタの場合、関連するリソースは "included" 項目に集められます。JSON アダプタと Attributes アダプタの場合は、関連するリソースは属性の中でレンダリングされます。

JSON API アダプタのみ、関連付けられたリソースのどの属性がレンダリングされるかを指定することができます。この機能は sparse fieldset と呼ばれています。

  render json: @posts, include: 'comments', fields: { comments: ['content', 'created_at'] }

セキュリティに関する考慮事項

含まれるオプションはクエリパラメータから取得される可能性があるため(つまりユーザーがコントロールできる)

  render json: @posts, include: params[:include]

ユーザーは include=** を渡すことができます。

ユーザーが指定する include を適切にフィルタリングすることをお勧めします。

高度なアダプタの設定

アダプタを登録する

上記のように、デフォルトのアダプタは指定したクラスを使用するように設定することができます。

たとえば、レンダリングするときは、アダプタはクラスあるいはシンボルでも指定することができます。
たとえば、:great_example , ActiveModelSerializers::Adapter::GreatExample のように、シンボルで指定されたときは、アダプタは登録されたものでなければなりません。

アダプタを登録する2つの方法があります。

1) 一番シンプルな方法は ActiveModelSerializers::Adapter::Base を継承することです。下記の例は Example::UsefulAdapter"example/useful_adapter" として登録しています。

module Example
  class UsefulAdapter < ActiveModelSerializers::Adapter::Base
  end
end

登録された名前がアンダースコアのネームスペースとクラスであることに気がつくと思います。

ActiveModelSerializers::Adapter::Base を継承したとき、秘密裏にそのサブクラスは ("example/useful_adapter" を Example::UsefulAdapter とする)という風に登録されます。

2) ActiveModelSerializers::Adapter クラスの register メソッドを直接呼び出すことで、どんなクラスでもアダプタとして登録することができます。下記の例では、MyAdapter:special_adapter として登録しています。

class MyAdapter; end
ActiveModelSerializers::Adapter.register(:special_adapter, MyAdapter)

アダプタの検索

メソッド 返り値
ActiveModelSerializers::Adapter.adapter_map すべてのアダプタのハッシュを返す。 { adapter_name => adapter_class }
ActiveModelSerializers::Adapter.adapters すべての adapter_names のソートされた配列を返す。
ActiveModelSerializers::Adapter.lookup(name_or_klass) adapter_classを返す。もし見つからない場合は、ActiveModelSerializers::Adapter::UnknownAdapter エラーが起こる。
ActiveModelSerializers::Adapter.adapter_class(adapter) ActiveModelSerializers::Adapter.lookup(adapter) に対する移譲。
ActiveModelSerializers::Adapter.configured_adapter ActiveModelSerializers::Adapter.lookup(config.adapter) を実行する便利なメソッド。

登録されたアダプタの名前は常にストリングです。しかし、シンボル、ストリングどちらでも検索することができます。
get(:my_adapter)get("MyAdapter") のどちらも使用できるように、シンボルとストリングはアンダースコアで変換されます。

詳細は the Adapter class on GitHub をご覧ください。

Caching

警告

現在、AMSのキャッシュには問題があります。キャッシュはパフォーマンスを改善しません。キャッシュを行うと、アプリケーションの速度を上昇させるのではなく、速度を低下させる場合があります。本番環境で使用する前に、実装するキャッシュをベンチマークすることをお勧めします。


シリアライザーをキャッシュするには、cache を呼び出してオプションを渡します。オプションは ActiveSupport::Cache::Store と同じです。それに加えて、"#{key}/#{object.id}-#{object.updated_at}" パターンのオブジェクトキャッシュのプレフィックスが入る key オプションもあります。

キャッシュのサポートは、複数のリクエスト間でキャッシュされたオブジェクトを使用するように最適化されています。show リクエストでキャッシュされたオブジェクトは index リクエストで再利用されます。もし別のキャッシュされたシリアライザーとリレーションがある場合は、そのリレーションは自動的に作成および再利用されます。

[注意] すべてのオブジェクトは個別にキャッシュされます。

[注意] キャッシュは、オブジェクトが更新されると自動的に期限切れになりますが、削除されません。

cache(options = nil) # options: ```{key, expires_in, compress, force, race_condition_ttl}```

以下の例をご覧ください。

class PostSerializer < ActiveModel::Serializer
  cache key: 'post', expires_in: 3.hours
  attributes :title, :body

  has_many :comments
end

この例では、すべての Post オブジェクトは "post/#{post.id}-#{post.updated_at}" キーでキャッシュされます。必要に応じてこのキーを使用してキャッシュを期限切れにすることができますが、この場合、3時間後に自動的に期限切れになります。

Fragment Caching

完全にキャッシュすべきではないAPIエンドポイントがある場合でも、属性とリレーションに対してフラグメントキャッシュを使用することで最適化することができます。

cache メソッドの only または except オプションを使用することで、キャッシュを適用する属性を定義することができます。

[注意] キャッシュが適用されるのは自身のリレーションに対してです。

class PostSerializer < ActiveModel::Serializer
  cache key: 'post', expires_in: 3.hours, only: [:title]
  attributes :title, :body

  has_many :comments
end

Configuration Options

ActiveModelSerializers.config に下記の設定オプションを記載することができます。なるべくイニシャライザに記載するようにしてください。

一般

adapter

使用する adapter

設定可能な値:

  • :attributes (default)
  • :json
  • :json_api

serializer_lookup_enabled

自動でシリアライザの検索を可能にします。

設定可能な値:

  • true (デフォルト)
  • false

false を設定したときは、シリアライザを明示的に指定しなければなりません。

key_transform

使用する key transform

オプション 結果
:camel ExampleKey
:camel_lower exampleKey
:dash example-key
:unaltered 元の変更されていないキー
:underscore example_key
nil アダプタのデフォルトを使用

各アダプタにはデフォルトのキー変換が設定されています。

アダプタ デフォルトのキー変換
Attributes :unaltered
Json :unaltered
JsonApi :dash

config.key_transform はアダプタの持つデフォルト設定をグローバルにオーバーライドします。アダプタはこの設定よりもレンダリング時のオプションである :key_transform を優先します。

注意: キー変換はコンピューターリソースを多く使う操作です。キー変換が不必要な場合は、config.key_transform:unaltered を設定すると、パーフォマンスが向上します。

default_includes

デフォルトでシリアライズするリレーションシップです。デフォルトでは、'*' が設定されていて、これは関連するオブジェクトの1レベル目を含みます。詳細は、includes をご覧ください。

serializer_lookup_chain

シリアライザがどのように検索されるかを設定します。デフォルトでは、ルックアップチェインには下記が設定されています。

ActiveModelSerializers::LookupChain::DEFAULT

これは下記の記述の略記です。

[
  ActiveModelSerializers::LookupChain::BY_PARENT_SERIALIZER,
  ActiveModelSerializers::LookupChain::BY_NAMESPACE,
  ActiveModelSerializers::LookupChain::BY_RESOURCE_NAMESPACE,
  ActiveModelSerializers::LookupChain::BY_RESOURCE
]

各配列の項目は手順を表しています。シリアライザ検索の手順は、 resource_class, serializer_class, namespace の3つの引数で生成されます。

次のことに注意してください:
- resource_class はレンダリングされるリソースのクラスです。
- デフォルトでは serializer_classActiveModel::Serializer です。
- 関連付けの検索においては、それは親シリアライザになります。
- namespace はコントローラーのネームスペースか任意の指定された namespace render optionnamespace のどちらかです。

設定例は次の通りになります。

ActiveModelSerializers.config.serializer_lookup_chain = [
  lambda do |resource_class, serializer_class, namespace|
    "API::#{namespace}::#{resource_class}"
  end
]

もしすでに存在するルックアップチェインを追加したいときは、unshift を使ってください。

ActiveModelSerializers.config.serializer_lookup_chain.unshift(
  lambda do |resource_class, serializer_class, namespace|
    # ...
  end
)

詳細は lookup_chain.rb をご覧ください。

use_sha1_digests

シリアライザをキャッシュするときに内部的に使用するハッシュアルゴリズムを決定します。

設定可能な値:

  • true
  • false (デフォルト)

この値が true のときは、ActiveModelSerializers は SHA1 を使用します。それ以外の場合、デフォルトで MD5 が使用されます。
この値を変更すると、シリアライザのキャッシュが無効になる可能性があることに注意してください。

JSON API

jsonapi_resource_type

シリアライザで明確に指定されていないときに、リソースの type が単数形と複数形のどちらなのかを設定します。

設定可能な値:

  • :singular
  • :plural (デフォルト)

jsonapi_namespace_separator

type 属性をレンダリングするために、ネームスペースのあるモデルの区切り文字列を設定してください。

区切り 例: Admin::User
'-' (デフォルト) 'admin-users'
'--' (推奨) 'admin--users'

詳細な議論は Recommendation for dasherizing (kebab-case-ing) namespaced object, such as Admin::User をご覧ください。

jsonapi_include_toplevel_object

レスポンスドキュメントに top level jsonapi member を含める。

設定可能な値:

  • true
  • false (デフォルト)

jsonapi_version

APIが準拠している仕様の最新バージョン。

デフォルト: '1.0'.

jsonapi_include_toplevel_objecttrue のときに使用されます。

jsonapi_toplevel_meta

オプションの最上位メタデータです。空の場合は含まれません。

デフォルト: {}.

jsonapi_include_toplevel_objecttrue のときに使用されます。

jsonapi_use_foreign_key_on_belongs_to_relationship

true を設定すると、関連付けあるいはシリアライザを呼び出さずに、リレーションシップはリソースオブジェクトの識別子を決定します。これは関連付けオブジェクトの呼び出しが不要なクエリをトリガーするときに便利です。

たとえば、commentpost に属し、コメントが外部キーとして post_id を使うとき、関連付けオプションの comment.post_idtype としてリソースオブジェクト識別子 id を決定します。
あるいは単純に、belongs_to :post, type: :posts, foreign_key: :post_id として動作します。

注意: インスタンス化をしないと関連付けオブジェクトのタイプを決定できないため、ポリモーフィックリレーションではこのオプションは効果がありません。

デフォルト: false

フック

ActiveModelSerializers が読み込まれたときにフックを実行するためには、ActiveSupport.on_load(:action_controller) do end を使用してください。

Deserialization

現在、これは実験的な機能です。インターフェースは変わる可能性があります。

JSON API

ActiveModelSerializers::Deserialization には jsonapi_parsejsonapi_parse! の2つのメソッドが定義されています。それらは、JSON API ペイロードを表す Hash または ActionController::Parameters のインスタンスを受け取り、モデルの作成・更新に直接使用できるハッシュを返します。バングバージョンはパースが失敗すると InvalidDocument 例外を発生させますが、セーフバージョンは空ハッシュを返すだけです。

  • パラメーター
    • ドキュメント: Hash または ActionController::Parameters インスタンス
    • オプション:
    • only: ホワイトリストの対象となるフィールドの Array
    • except: ブラックリストの対象となるフィールドの Array
    • keys: 名前を変更する必要があるフィールド の Hash(例 { :author => :user, :date => :created_at })

class PostsController < ActionController::Base
  def create
    Post.create(create_params)
  end

  def create_params
    ActiveModelSerializers::Deserialization.jsonapi_parse(params, only: [:title, :content, :author])
  end
end

下記が与えられる JSON API ドキュメントです。

document = {
  'data' => {
    'id' => 1,
    'type' => 'post',
    'attributes' => {
      'title' => 'Title 1',
      'date' => '2015-12-20'
    },
    'relationships' => {
      'author' => {
        'data' => {
          'type' => 'user',
          'id' => '2'
        }
      },
      'second_author' => {
        'data' => nil
      },
      'comments' => {
        'data' => [{
          'type' => 'comment',
          'id' => '3'
        },{
          'type' => 'comment',
          'id' => '4'
        }]
      }
    }
  }
}

オプションを指定せずにドキュメント全体をパースすることができます。

ActiveModelSerializers::Deserialization.jsonapi_parse(document)
#=>
# {
#   title: 'Title 1',
#   date: '2015-12-20',
#   author_id: 2,
#   second_author_id: nil
#   comment_ids: [3, 4]
# }

フィールド、リレーション、およびポリモーフィックリレーションは、オプションを介して指定することができます。

ActiveModelSerializers::Deserialization
  .jsonapi_parse(document, only: [:title, :date, :author],
                           keys: { date: :published_at },
                           polymorphic: [:author])
#=>
# {
#   title: 'Title 1',
#   published_at: '2015-12-20',
#   author_id: '2',
#   author_type: 'user'
# }

Attributes/Json

現在、これらのアダプターの deserialization はありません。

Fields

もし何らかの理由で返すフィールドを制限する必要がある場合は、fields オプションを使用する必要があります。

たとえば、次のようなシリアライザーがあり、

class UserSerializer < ActiveModel::Serializer
  attributes :access_token, :first_name, :last_name
end

特定のコントローラーでは、access_token のみを返したい場合に fields オプションが役立ちます。

class AnonymousController < ApplicationController
  def create
    render json: User.create(activation_state: 'anonymous'), fields: [:access_token], status: 201
  end
end

これは json および attributes アダプタに対してのみ有効であることに注意してください。 json_api アダプタの場合は下記を使用します。

render json: @user, fields: { users: [:access_token] }

ここでは users は JSONAPI のタイプです。

Getting Started

シリアライザーの作成

新しいシリアライザーを作成する最も簡単な方法は、新しいリソースを生成することです。これによって、シリアライザーの作成も同時に行われます。

$ rails g resource post title:string body:string

これにより新しいモデルのシリアライザーが app/serializers/post_serializer.rb に作成されます。シリアライザージェネレーターを使用して、既存のモデルのシリアライザーを作成することもできます。

$ rails g serializer post

作成されたシリアライザーにはモデルに基づいて、基本的な attributeshas_many/has_one/belongs_to の宣言が記載されます。

以下の例をご覧ください。

class PostSerializer < ActiveModel::Serializer
  attributes :title, :body

  has_many :comments
  has_one :author
end
class CommentSerializer < ActiveModel::Serializer
  attributes :name, :body

  belongs_to :post
end

宣言されている属性の名前は、シリアライズされるモデルの属性のホワイトリストになります。

has_many has_one belongs_to の宣言はリソース間のリレーションを記述しています。デフォルトでは、Post をシリアライズすると、Comments もシリアライズされます。

詳細については、Serializers を参照してください。

ネームスペースのあるモデル

Api::V1::Post のようなネームスペース内のモデルをシリアライズするとき、ActiveModelSerializers は対応するシリアライザーが同じネームスペースの中(Api::V1::PostSerializer)にいることを期待します。

モデルの関連とネストされたシリアライザー

次のような関連付けを持つモデルのシリアライザーを宣言する場合

class PostSerializer < ActiveModel::Serializer
  has_many :comments
end

ActiveModelSerializers は優先的に PostSerializer::CommentSerializer を探し、それが見つからない場合は ::CommentSerializer を探します。これにより、モデルを他のモデルの関連付けとしてシリアライズする方法をより詳細に制御できます。

たとえば、下記をご覧ください。

class CommentSerializer < ActiveModel::Serializer
  attributes :body, :date, :nb_likes
end

class PostSerializer < ActiveModel::Serializer
  has_many :comments
  class CommentSerializer < ActiveModel::Serializer
    attributes :body_short
  end
end

ActiveModelSerializersは、Post の一部として Comment をシリアライズするときにPostSerializer::CommentSerializer を使用します。そのため、:body_short 属性のみが含まれます。しかし、Comment を直接シリアライズするときは ::CommentSerializer を使用します。その際は、:body, :date, :nb_likes 属性が含まれます。

ApplicationSerializer の拡張

デフォルトでは、新しいシリアライザーは ActiveModel::Serializer を継承しています。もしシリアライザー全体でふるまいを共有したいときは、app/serializers/application_serializer.rbApplicationSerializer を作成することができます。

class ApplicationSerializer < ActiveModel::Serializer
end

その後、新しく生成されたシリアライザーは自動的に ApplicationSerializer を継承します。

$ rails g serializer post

下記が生成されたシリアライザーです。

class PostSerializer < ApplicationSerializer
  attributes :id
end

Rails との統合

ActiveModelSerializers は Rails アプリと自動的に統合されるので、コントローラーを更新する必要はありません。
下記はコントローラーの例です。

class PostsController < ApplicationController

  def show
    @post = Post.find(params[:id])
    render json: @post
  end

end

もしリンク生成の Rails url ヘルパーを使用したいときは(例:link(:resources) { resources_url } )、Rails.application.routes.default_url_options を設定してください。

Rails.application.routes.default_url_options = {
    host: 'example.com'
}

Instrumentation

ActiveModelSerializers は ActiveSupport::Notification API を使用します。これにより、ロギングなどのイベントを購読することができます。

Events

名前

render.active_model_serializers

ペイロード (例)

{
  serializer: PostSerializer,
  adapter: ActiveModelSerializers::Adapter::Attributes
}

購読

ActiveSupport::Notifications.subscribe 'render.active_model_serializers' do |name, started, finished, unique_id, data|
  # 任意の処理
end
ActiveSupport::Notifications.subscribe 'render.active_model_serializers' do |*args|
  event = ActiveSupport::Notifications::Event.new(*args)
  # event.payload
  # 任意の処理
end

LogSubscriber

ActiveModelSerializers には render.active_model_serializers に付随する ActiveModelSerializers::LogSubscriber が含まれています。

Key Transforms

Key Transforms は、シリアライズされたレスポンスの中で参照されるものも含めてキーの文字形式を変更します。

提供されるキー変換の種類:

オプション 結果
:camel ExampleKey
:camel_lower exampleKey
:dash example-key
:unaltered 元々のキーを使用
:underscore example_key
nil アダプタのデフォルトを使用

キー変換の優先順位は下記の通りです:

Adapter option

key_transform はレンダリングのオプションとして提供されます。

render json: posts, each_serializer: PostSerializer, key_transform: :camel_lower

Configuration option

key_transformActiveModelSerializers.config.key_transform に設定します。

ActiveModelSerializers.config.key_transform = :camel_lower

Adapter default

各アダプタはデフォルトの変換設定を持っています:

アダプタ デフォルト設定
Json :unaltered
JsonApi :dash

Logging

Rails アプリケーションのデフォルトのロガーは Rails.logger です。

Rails.logger がないときは、標準出力にログを出力する ActiveSupport::TaggedLogging のインスタンスがデフォルトのロガーになります。

たとえば下記のように、イニシャライザでロガーをカスタマイズすることもできます。

ActiveModelSerializers.logger = Logger.new(STDOUT)

config/initializers/active_model_serializers.rb に下記を記載することで、ロガーを無効にすることもできます。

require 'active_model_serializers'
ActiveSupport::Notifications.unsubscribe(ActiveModelSerializers::Logging::RENDER_EVENT)

Rendering

暗黙のシリアライザ

コントローラーで render :json を使うとき、Rails はまず最初にオブジェクトのシリアライザを探し、もし利用可能ならそのシリアライザを使用します。

class PostsController < ApplicationController
  def show
    @post = Post.find(params[:id])

    render json: @post
  end
end

上記の場合、Rails は PostSerializer を探し、それが存在する場合は、そのシリアライザを使用して Post をシリアライズします。

明示的なシリアライザ

もしデフォルト以外のシリアライザを使いたいときは、render メソッドに明示的にシリアライザを渡すことができます。

1. 単一のリソース

  render json: @post, serializer: PostPreviewSerializer

2. リソースのコレクション

各々のリソースに対して each_serializer でシリアライザを指定してください。

render json: @posts, each_serializer: PostPreviewSerializer

コレクションのデフォルトのシリアライザは CollectionSerializer です。

serializer オプションでコレクションシリアライザを指定してください。

render json: @posts, serializer: CollectionSerializer, each_serializer: PostPreviewSerializer

non-ActiveRecord オブジェクトのシリアライズ

README をご覧ください。

SerializableResource options

README をご覧ください。

adapter_opts

fields

json または attributes アダプタを使用している場合、 fields オプションを使用できます。

render json: @user, fields: [:access_token]

詳細は Fields をご覧ください。

adapter

このオプションを使用することで、登録済みのアダプタを渡して明示的にアダプタを設定できます。オプションは :attributes, :json, または :json_api です。

ActiveModel::Serializer.config.adapter = :json_api

key_transform


render json: posts, each_serializer: PostSerializer, key_transform: :camel_lower

詳細は Key Transforms をご覧ください。

meta

meta 項目は非標準のメタ情報を含むために使用することができます。meta はレスポンスにおいていくつかの水準で利用されます。

トップレベル

レスポンスでトップレベルの meta を設定するときは、render の呼び出し時に meta を指定してください。

render json: @post, meta: { total: 10 }

meta_key オプションを使用することでキーをカスタマイズすることができます。

render json: @post, meta: { total: 10 }, meta_key: "custom_meta"

JsonApiJson アダプタのように root をサポートするアダプタを使用するときのみ、レスポンスに meta は含まれます。デフォルトアダプタである Attributesroot を持っていません。

リソースレベル

レスポンスでリソースレベルの meta を設定するには、シリアライザの中で下記の方法の内の一つを使って meta を定義してください。

単独の静的な文字列の場合

meta stuff: 'value'

ハッシュを含むブロックの場合

meta do
  {
    rating: 4,
    comments_count: object.comments.count
  }
end

links

たとえば link(:resources) { resources_url } のように、リンク生成のためにRailsのURLヘルパー使いたいときは、必ず Rails.application.routes.default_url_options をアプリケーションに設定してください。

トップレベル

JsonApi はトップレベルで指定する links object をサポートしています。render メソッドでそれを指定することができます。

  links_object = {
    href: "http://example.com/api/posts",
    meta: {
      count: 10
    }
  }
  render json: @posts, links: links_object

結果は下記になります。

{
  "data": [
    {
      "type": "posts",
      "id": "1",
      "attributes": {
        "title": "JSON API is awesome!",
        "body": "You should be using JSON API",
        "created": "2015-05-22T14:56:29.000Z",
        "updated": "2015-05-22T14:56:28.000Z"
      }
    }
  ],
  "links": {
    "href": "http://example.com/api/posts",
    "meta": {
      "count": 10
    }
  }
}

この機能は JsonApi に固有であるため、JsonApi Adapter を使用する必要があります。

リソースレベル

シリアライザの中で、下記の方法の内の一つを使ってそれぞれのリンクを定義してください。

静的な文字列の場合。

link :link_name, 'https://example.com/resource'

ブロックの場合。Rails を使うとURLヘルパーを使用することができます。
必ず Rails.application.routes.default_url_options をアプリケーションに設定してください。

link :link_name_ do
  "https://example.com/resource/#{object.id}"
end

link(:link_name) { "https://example.com/resource/#{object.id}" }

link(:link_name) { resource_url(object) }

link(:link_name) { url_for(controller: 'controller_name', action: 'index', only_path: false) }

serializer_opts

include

Adapters: Include Option をご覧ください。

Overriding the root key

ルートキーのオーバーライドはJSONアダプタのときのみ適用されます。

通常、リソースルートはシリアライズされるリソースのクラス名が使用されます。
たとえば、UserPostSerializer.new(UserPost.new) はアダプタのコレクション複数化ルールに応じて、user_post または user_posts をルートとしてシリアライズされます。

イニシャライザで JSON アダプタを使用するとき(ActiveModelSerializers.config.adapter = :json)、あるいは、render メソッドの呼び出し時に JSON アダプタを渡すと、render の引数としてルートキーを渡すことができます。

  render json: @user_post, root: "admin_post", adapter: :json

これは下記のようにレンダリングされます。

  {
    "admin_post": {
      "title": "how to do open source"
    }
  }

注意: デフォルトである Attributes アダプタはリソースルートを含みません。 :json_api アダプタを使用するときも単独のトップレベルのルートを作成することはできません。

namespace

シリアライザの検索に使用されるネームスペースはコントローラーがもとになっています。

暗黙的なネームスペースを設定するために、コントローラーに before filter を作成してください。

before_action do
  self.namespace_for_serializer = Api::V2
end

namespace オプションを render メソッドに渡すことができます。

@post = Post.first
render json: @post, namespace: Api::V2

これはシリアライザの検索に Api::V2::PostSerializer の存在を確認するように伝えます。
これによって、Api::V2::PostSerializer をシリアライザの検索時に探すようになります。もし @post に何らかのリレーションがレンダリングされるときは、そのリレーションは Api::V2 のネームスペースも使用します。

namespace は、ストリング・インターポーション(つまり to_s を呼び出すこと)によってネームスペースを表すことができる任意のオブジェクトにすることができます。

  • モジュール Api::V2
  • ストリング 'Api::V2'
  • シンボル :'Api::V2'

ストリングとシンボルを使うことで、 Ruby はトップレベルにネームスペースが定義されていると考えるので注意してください。

serializer

デフォルトではないシリアライザを使いたいときは、使用するシリアライザを指定してください。

単独のリソースのとき:

@post = Post.first
render json: @post, serializer: SpecialPostSerializer

コレクションのにおいて個々のアイテムに使うシリアライザを指定するときは(たとえば index アクションのとき)、 each_serializer を使用してください。

@posts = Post.all
render json: @posts, each_serializer: SpecialPostSerializer

scope

Serializers: Scope をご覧ください。

scope_name

Serializers: Scope をご覧ください。

render メソッドなしのシリアライザの使用

Usage outside of a controller をご覧ください。

ページネイション

How to add pagination links をご覧ください。

Serializers

シリアライザクラスが与えられた場合

class SomeSerializer < ActiveModel::Serializer
end

下記のメソッドを定義できます。

属性

::attributes メソッド

リソースの titlebody のシリアライズ化

シリアライザの記載 #attributes メソッドの返り値
attributes :title, :body { title: 'Some Title', body: 'Some Body' }
attributes :title, :body
def body "Special #{object.body}" end
{ title: 'Some Title', body: 'Special Some Body' }

::attribute メソッド

リソースの title のシリアライズ化

シリアライザの記載 #attributes メソッドの返り値
attribute :title { title: 'Some Title' }
attribute :title, key: :name { name: 'Some Title' }
attribute(:title) { 'A Different Title'} { title: 'A Different Title' }
attribute :title
def title 'A Different Title' end
{ title: 'A Different Title' }

if あるいは unless オプションは属性を条件付きにすることができます。if, unless はシリアライザのメソッド名のシンボル、あるいはラムダリテラルを受け取ります。

attribute :private_data, if: :is_current_user?
attribute :another_private_data, if: -> { scope.admin? }

def is_current_user?
  object.id == current_user.id
end

関連付け

The interface for associations is, generically:
関連付けのインターフェースは一般的に、

association_type(association_name, options, &block)

の形を取ります。

  • association_typehas_one, has_many, belongs_to のいずれかです。
  • association_name はシリアライザが呼び出すメソッド名です。
  • 任意: options には下記を設定することができます。
    • key: シリアライズされる関連付けに使用される名前。
    • serializer:
    • if:
    • unless:
    • virtual_value:
    • polymorphic: シリアライズされる関連付けにポリモーフィックなリレーションがネストされているときに定義してください。
    • type: JSON:API が使用されたときのリソースタイプ。特に belongs_to のリレーションで使用されます。
    • class_name: type が与えられていないときに type を決定するために使用されるストリングのモデル名。たとえば、class_name: "Comment" はタイプ comments を意味します。
    • foreign_key: 関連付けのオブジェクトの不必要な読み込みを避けるために、belongs_to リレーションシップにおいて JSON:API で使用されます。
    • namespace: シリアライザを検索するときと serializer オプションが指定されていないときに使用されます。親シリアライザの instance options の :namespace を遡ります。instance options の :namespace は render メソッドのオプションとして渡されます。詳細は、Rendering#namespace をご覧ください。
  • 任意: &block は関連付けの属性を返すコンテキストです。
    • association_name メソッドが呼び出されるのを防ぎます。
    • ブロックの戻り値は関連付けの値として使用されます。
    • ブロックに serializer を生成する。
    • JSON API の関連付けにおいて include_data falsedata キーがレンダリングされることを防ぐ。

::has_one メソッド

has_one :bio
has_one :blog, key: :site
has_one :blog, class_name: "Blog"
has_one :maker, virtual_value: { id: 1 }

has_one :blog do |serializer|
  serializer.cached_blog
end

def cached_blog
  cache_store.fetch("cached_blog:#{object.updated_at}") do
    Blog.find(object.blog_id)
  end
end
has_one :blog, if: :show_blog?
# ストリングあるいはラムダも使うことができる。
# has_one :blog, if: 'scope.admin?'
# has_one :blog, if: -> (serializer) { serializer.scope.admin? }
# has_one :blog, if: -> { scope.admin? }

def show_blog?
  scope.admin?
end

::has_many メソッド

has_many :comments
has_many :comments, key: :reviews
has_many :comments, serializer: CommentPreviewSerializer
has_many :comments, class_name: "Comment"
has_many :reviews, virtual_value: [{ id: 1 }, { id: 2 }]
has_many :comments, key: :last_comments do
  last(1)
end

::belongs_to メソッド

belongs_to :author, serializer: AuthorPreviewSerializer
belongs_to :author, key: :writer
belongs_to :author, class_name: "Author"
belongs_to :post
belongs_to :blog
def blog
  Blog.new(id: 999, name: 'Custom blog')
end

ポリモーフィックリレーション

ポリモーフィックリレーションは、他の関連付けのようにリレーションを指定することでシリアライズされます。以下の例をご覧ください。

class PictureSerializer < ActiveModel::Serializer
  has_one :imageable
end

overriding serializer_for を行うことによって、シリアライザを指定することができます。ポリモーフィックリレーションの詳細については、各アダプタの tests をご覧ください。

キャッシュ

::cache メソッド

cache key: 'post', expires_in: 0.1, skip_digest: true
cache expires_in: 1.day, skip_digest: true
cache key: 'writer', skip_digest: true
cache only: [:name], skip_digest: true
cache except: [:content], skip_digest: true
cache key: 'blog'
cache only: [:id]

#cache_key メソッド

# Uses a custom non-time-based cache key
def cache_key
  "#{self.class.name.downcase}/#{self.id}"
end

その他

::type メソッド

:json_api アダプタを使用するとき、::type メソッドはシリアライザでレンダリングされる JSONAPI type を定義します。

:json アダプタを使用するとき、::type メソッドはルートキーの名前を定義します。

::type メソッドは StringSymbol のどちらもパラメーターとして受け取ります。

注意: このメソッドは、:json_api あるいは :json アダプタを使用する場合にのみ役立ちます。

class UserProfileSerializer < ActiveModel::Serializer
  type 'profile'

  attribute :name
end
class AuthorProfileSerializer < ActiveModel::Serializer
  type :profile

  attribute :name
end

:json_api アダプタの場合、上記のシリアライザは下記のようにレンダリングされます。

{
  "data": {
    "id": "1",
    "type": "profile",
    "attributes": {
      "name": "Julia"
    }
  }
}

:json アダプタの場合、上記のシリアライザは下記のようにレンダリングされます。

{
  "profile": {
    "name": "Julia"
  }
}

::link メソッド

link :self do
  href "https://example.com/link_author/#{object.id}"
end
link(:author) { link_author_url(object) }
link(:link_authors) { link_authors_url }
link :other, 'https://example.com/resource'
link(:posts) { link_author_posts_url(object) }

属性のように、links はオプションのコンディションをサポートします。

link(:secret, if: :internal?) { object.secret_link }

def internal?
  instance_options[:context] == :internal
end

#object メソッド

シリアライズされているオブジェクトを返します。

#root メソッド

JSON アダプタに含まれるリソースルートを返します。Adapters Document にあるように、Attribute アダプタ(デフォルト)と JSON API アダプタはトップレベルにルートキーを含みません。
デフォルトでは、リソースルートはシリアライズされるオブジェクトクラスの model_name から生成されます。

ルートを指定する方法はいくつかあります:
* Overriding the root key
* Setting type
* root: 'specific_name' のようにシリアライザの初期化をするときに、root オプションを指定する。

ActiveModelSerializers::SerializableResource.new(foo, root: 'bar')

#scope メソッド

外部メソッドへのアクセスをシリアライザに含めることができます。

シリアライザに認可コンテキストを提供することを目的としているため、 たとえば、管理者に投稿のすべてのコメントを表示するか、あるいはそうでなければ公開されたコメントのみを表示するということができます。

  • scopeoptions[:scope] から来ているシリアライザインスタンスのメソッドです。nil であることもあります。
  • scope_name は新しいシリアライザに渡されるオプションです(options[:scope_name])。シリアライザは、scope を呼び出す名前でメソッドを定義します。例 def current_user; scope; end

注意: シリアライザインスタンスがその名前に応答するメソッドをすでに持っている場合は、メソッドは定義されません。

いくつか例をご覧ください。

まず、通常のシナリオなので、シリアライザがコントローラーでインスタンス化されると仮定します。
シリアライズを行うコンテキストを controller と呼びます。

options Serializer#scope method definition
scope: current_user, scope_name: :current_user current_user Serializer#current_user calls controller.current_user
scope: view_context, scope_name: :view_context view_context Serializer#view_context calls controller.view_context

スコープを利用して、カレントユーザーに関連するオブジェクトをカスタマイズできます。

たとえば、現在のユーザーに表示される投稿を、そのユーザーが作成した投稿に制限することができます。

class PostSerializer < ActiveModel::Serializer
  attributes :id, :title, :body

  # scope comments to those created_by the current user
  has_many :comments do
    object.comments.where(created_by: current_user)
  end
end

メソッドを上記のように記述するか、object.comments.where(created_by:scope) として記述するかは好みの問題です。(scope_name は設定されているものとします)

スコープには、すべての利用可能なコントローラーの参照を設定できることに注意してください。これを利用すると、他のデータスコープまたはプレゼンテーションヘルパーへのアクセスを提供することができます。

コントローラーの認可コンテキスト

コントローラーでは、scope/scope_name オプションは serialization_scope method と同じです。
デフォルトでは、serialization_scope には :current_user が設定されています。

具体的には、scope_name のデフォルトは :current_user です。ただ、serialization_scope :view_context を設定することもできます。scope_name が存在してコントローラーが scope_name に応答するとき、scopesend(scope_name) に設定されます。

そのため、render :json を呼び出したとき、シリアライザの中ではcurrent_user が現在の認可範囲としてコントローラーから与えられます。

重要: スコープはレンダリング時に設定され、すべてのリクエストで current_user が呼び出されるわけではないので、スコープをカスタマイズしたくなるかもしれません。このことは、バージョン0.9でも問題となっていました。

current_user から view_context にスコープを変更することができます。この変更は ActionController::Base のサブクラスに記載されます。

class SomeController < ActionController::Base
+  serialization_scope :view_context

  def current_user
    User.new(id: 2, name: 'Bob', admin: true)
  end

  def edit
    user = User.new(id: 1, name: 'Pete')
    render json: user, serializer: AdminUserSerializer, adapter: :json_api
  end
end

下記のように、シリアライザの中で view_context メソッドを使用できます。

class AdminUserSerializer < ActiveModel::Serializer
  attributes :id, :name, :can_edit

  def can_edit?
+    view_context.current_user.admin?
  end
end

#edit アクションをレンダリングすると下記の結果が得られます。

{"data":{"id":"1","type":"users","attributes":{"name":"Pete","can_edit":true}}}

ここでは、can_editview_context.current_user.admin? の値(trueが返る)です。

また、特定のアクションに対して serialization_scope として設定するものを指示することもできます。

下記の例では、Admin::PostSerializer に対してのみ admin_user を使用し、それ以外では current_user を使用しています。

class PostsController < ActionController::Base

  before_action only: :edit do
    self.class.serialization_scope :admin_user
  end

  def show
    render json: @post, serializer: PostSerializer
  end

  def edit
    @post.save
    render json: @post, serializer: Admin::PostSerializer
  end

  private

  def admin_user
    User.new(id: 2, name: 'Bob', admin: true)
  end

  def current_user
    User.new(id: 2, name: 'Bob', admin: false)
  end
end

異なるリソースを読み込む別のコントローラーメソッドやヘルパーへの参照などのように、目的のスコープを提供するどんなコントローラーの参照も利用可能なことに注意してください。たとえば、ActionController::APIActionView::ViewContext を含まず、serialization_scope を使用して任意のヘルパーをシリアライザに渡すためには異なる参照を必要とします。

#read_attribute_for_serialization(key) メソッド

たとえば、read_attribute_for_serialization(:title) #=> 'Hello World' のように、与えられたキーがシリアライズされた値。

#links メソッド

links ノードを変更します。デフォルトでは、このノードには、::link メソッドを使用して設定された属性が入力されます。links: nil を使用することで、links ノードを除去します。

ActiveModelSerializers::SerializableResource.new(
  @post,
  adapter: :json_api,
  links: {
    self: {
      href: 'http://example.com/posts',
      meta: {
        stuff: 'value'
      }
    }
  }
)

#json_key メソッド

リソースルートとしてアダプタに使用されるキーを返します。詳細は、root をご覧ください。

Post(title: string, body: text)Comment(name: string, body: text, post_id: integer) の2つのモデルがあるとき、2つのシリアライザを作成することになります。

class PostSerializer < ActiveModel::Serializer
  cache key: 'posts', expires_in: 3.hours
  attributes :title, :body

  has_many :comments
end
class CommentSerializer < ActiveModel::Serializer
  attributes :name, :body

  belongs_to :post
end

一般的な ActiveModelSerializers の使い方としては、これらのシリアライザのクラスを記載・生成します。

詳細情報

詳細は the Serializer class on GitHub をご覧ください。

関連付けメソッドのオーバーライド

関連付けをオーバーライドするには、ブロックと一緒に has_many, has_one, belongs_to を呼び出します。

class PostSerializer < ActiveModel::Serializer
  has_many :comments do
    object.comments.active
  end
end

属性メソッドのオーバーライド

属性をオーバーライドするには、ブロックと一緒に attribute を呼び出します。

class PostSerializer < ActiveModel::Serializer
  attribute :body do
    object.body.downcase
  end
end

関連付けられたシリアライザ検索のオーバーライド

関連付けのために特定のシリアライザの検索を定義したいときは、ActiveModel::Serializer.serializer_for メソッドをオーバーライドすることで定義した条件に基づいてシリアライザクラスを返すことができます。

class MySerializer < ActiveModel::Serializer
  def self.serializer_for(model, options)
    return SparseAdminSerializer if model.class.name == 'Admin'
    super
  end

  # the rest of the serializer
end

Read Me ActiveModelSerializers

About

ActiveModelSerializers はJSON生成に設定よりも規約をもたらします。

ActiveModelSerializers は serializersadapters の2つのコンポーネントを通して動作します。

シリアライザはどの属性とリレーションシップがシリアライズされるかを記載します。

アダプタはどのように属性とリレーションがシリアライズされるかを記載します。

SerializableResource はリソース、アダプタ、シリアライザを調整してリソースをシリアライズします。SerializableResource は Rails JSON Renderer に使用される #as_json, #to_json , #serializable_hash メソッドを持っています。(実際は SerializableResource はこれらのメソッドをアダプタに移譲します。)

デフォルトでは、ActiveModelSerializers は Attributes アダプタ を使用します(JSON のルートキーはありません)。
しかし、私たちは jsonapi.org/format で指定された バージョン1.0の形式に追従する JsonApi アダプタ を使用することを強く勧めます。
下記のセクションでアダプタの変更方法を確認してください。

0.10.x0.9.x0.8.x と後方互換性はありません

0.10.x0.8.0 のコードをもとにしていますが、より柔軟なアーキテクチャーを持っています。私たちはあなたの手助けを歓迎します。貢献の仕方

インストール

下記の行を Gemfile に追加してください。

gem 'active_model_serializers', '~> 0.10.0'

そして下記を実行してください:

$ bundle

入門

基礎的なことについては Getting Started をご覧ください。

詳細情報は GuidesHigh-level behavior に記載されています。

Getting Help

もしバグを見つけた場合は、 Issue を報告して contributing guide を見てください。

質問があるときは、Stack Overflow に投稿してください.

チャットで話したいときは、community slack に参加してください。

ドキュメント

もし https://github.com/rails-api/active_model_serializers でこの文章を読んでいるなら、あなたは master ブランチのドキュメントを読んでいます。master ブランチ はまだリリースされていない機能を含んでいる可能性があります。関連するドキュメントについては、以下をご覧ください。

高レベルの動作

adapters からアダプタを選択してください。

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

シリアライズ可能なモデル が与えられた場合。

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

下記のようにイニシャライズします。

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

シリアライズ可能なモデルのシリアライザが与えられた場合、

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

モデルは下記のようにシリアライズされます。

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

SerializableResource はアダプタに移譲を行い、アダプタは下記のように構築します。

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

アダプタはシリアライザの属性と関連付けを構成します(別名 includes)。

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

アーキテクチャ

このセクションは ActiveModelSerializers の 0.10.x バージョンのアーキテクチャに焦点を当てています。
もし 0.8 あるいは 0.9 のバージョンに興味がある場合は、0.8 README ,
0.9 README を参照してください。

オリジナルの文章はこちらでも見ることができます。

ActiveModel::Serializer

ActiveModel::Serializerシリアライズ可能なリソース をラップし、attributes メソッドなどを使えるようにします。
ActiveModel::Serializer はリソースのシリアライズにおいてどの属性と関連付けを表すかを指定します。
ActiveModel::Serializer はアダプタに自身の属性を JSON ドキュメントに変換するように要求します。ActiveModel::Serializer だけではシリアライズを行うことはできません。
アダプタを presenter として考えると良いかもしれません。

ActiveModel::CollectionSerializer

ActiveModel::CollectionSerializer はリソースの集合を複数のシリアライザとして表します。もしシリアライザがない場合は基本要素を表します。

ActiveModelSerializers::Adapter::Base

ActiveModelSerializers::Adapter::Base はシリアライザから生成された JSON ドキュメントの構造を記述します。たとえば、Attributes アダプタは各シリアライザを未変更の属性として表します。JsonApi アダプタはシリアライザを JSON API ドキュメントとして表します。

ActiveModelSerializers::SerializableResource

ActiveModelSerializers::SerializableResource は to_jsonas_json メソッドに応答するオブジェクトに対してシリアライザとアダプタを調整するように動作します。ActiveModelSerializers::SerializableResource はコントローラーにおいてレンダリング時にシリアライズするリソースを要約するために使用されます。しかし、コントローラーの外でも利用することはできます。

Primitive handling

定義: プリミティブは通常、文字列か配列です。それらに対してシリアライザは定義されていません。リソースが JSON に変換されるとき(as_json あるいは to_json メソッド)にそれらはシリアライズされます。(以下は、シリアライザのないオブジェクトにも適用されます。)

  • ActiveModelSerializers は render json: に渡されたプリミティブをハンドリングしません。

内部的には、コントローラーでシリアライザが見つけられない場合は、リソースは ActiveModelSerializers によって処理されません。

  • しかし、プリミティブな値が属性、あるいはコレクションの1つであるとき、それは変更されません。

コレクションとコレクションシリアライザ(CollectionSerializer)をシリアライズし、リソースに対応するシリアライザを識別できないとき、:no_serializer をスローします。
たとえば、Reflection#build_association によってキャッチされ、関連付けの値が直接設定されたときです。

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

(これはアダプタによって serializer.associations(*) として呼び出されます。)

オプションのパースの行われ方

高レベルの概要:

  • コレクションについて
    • :serializer はコレクションに対するシリアライザを指定します。
    • :each_serializer はコレクションの中の各シリアライザを指定します。
  • 単独のリソースにおいては、:serializer オプションはそのリソースのシリアライザです。
  • オプションはシリアライザのオプションとアダプタのオプションに別けられます。アダプタオプションのキーは ADAPTER_OPTION_KEYS から指定されます。残りのオプションはすべてシリアライザのオプションです。

詳細:

  1. ActionController::Serialization
    1. serializable_resource = ActiveModelSerializers::SerializableResource.new(resource, options)
    2. options are partitioned into adapter_opts and everything else (serializer_opts).optionsadapter_opts とその他(serializer_opts)に別れている。adapter_opts のキーは ActiveModelSerializers::SerializableResource::ADAPTER_OPTION_KEYS に定義されている。
  2. ActiveModelSerializers::SerializableResource
    1. if serializable_resource.serializer? (シリアライザが存在し、アダプタが使用されている)
    2. そこでは serializer?use_adapter? && !!(serializer) を行なっています。
      • use_adapter?: 明示的なアダプタが与えられていないとき、あるいは明示的な値が truthy のときに True を返す。明示的なアダプタが falsy のときに False を返す。
      • serializer:
        1. 明示的に :serializer オプションで指定したシリアライザ。
        2. 暗黙的に ActiveModel::Serializer.serializer_for(resource) から来るシリアライザ
    3. serializer を確認することを副次効果:
      • :serializer オプションは serializer_opts ハッシュから除去されます。
      • :each_serializer オプションがあるとき、:each_serializer オプションは除去されて :serializer として設定されます。
    4. シリアライザとアダプタは下記のように作成されます。
      1. serializer_instance = serializer.new(resource, serializer_opts)
      2. adapter_instance = ActiveModel::Serializer::Adapter.create(serializer_instance, adapter_opts)
  3. ActiveModel::Serializer::CollectionSerializer#new
    1. serializer_instanceCollectionSerializer:serializer オプションが存在するとき、そのシリアライザは各リソースに渡されます。
  4. ActiveModel::Serializer#attributes はシリアライザに定義されたリソースの属性をアダプタによって取得するために使用されます。

(Rails では、Rails の JSON レンダリングによるリソースのシリアライズ化において as_json(options) あるいは to_json(options) メソッドにも options は 渡されます。ActiveModelSerializers の機能ではないですがこのことについて知っておくことは重要です。)

「シリアライズ可能なリソース」とはどのようなものか?

  • ActiveRecord::Baseオブジェクト。
  • Lint (code) 渡す任意の Ruby オブジェクト

ActiveModelSerializers は ActiveModelSerializers::Model を提供しています。それはシンプルなシリアライズ可能な PORO (Plain-Old Ruby Object) です。

ActiveModelSerializers::Model は参考実装としてもあるいは本番コードの中でも使うことができます。

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

MyModel が ActiveRecord::Base オブジェクトかどうかに関わらず、MyModel のデフォルトのシリアライザは MyModelSerializer になります。

コントローラの外では、それらのルールはレコードの場合とまったく同じです。

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

は下記と同様にシリアライズされます。

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

Semantic Versioning

This project adheres to semver

Contributing

See CONTRIBUTING.md

98
79
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
98
79