LoginSignup
98
68

More than 5 years have passed since last update.

ActiveModel::Serializersでネストされたリソースを扱う

Last updated at Posted at 2016-09-01

環境

Rails 5.0.0.1
active_model_serializers 0.10.2

概要

リソースを2段階以上ネストしたときに、2段階目以降がシリアライズの結果に入ってこない。
include オプションを使う。

詳細

テーブル

こんな感じ。

テーブル名 カラム
hoges id, hogehoge
fugas id, hoge_id, fugafuga
bars id, fuga_id, barbar

モデル

普通にhas_manyになっている。

class Hoge < ApplicationRecord
  has_many :fugas
end

class Fuga < ApplicationRecord
  has_many :bars
end

class Bar < ApplicationRecord
end

Serializer

次のように書く。

# app/serializers/hoge_seralizer.rb
class HogeSerializer < ActiveModel::Serializer
  attributes :id, :hogehoge
  has_many :fugas

  class FugaSerializer < ActiveModel::Serializer
    attributes :id, :fugafuga
    has_many :bars

    class BarSerializer < ActiveModel::Serializer
      attributes :id, :barbar
    end
  end
end

注: ネストして書いたが、別のファイルに書いてもよい。両方書くと自分の中のクラスが優先される。
詳細は ここ の Model Associations and Nested Serializers っていうところにある。

Controller

Controllerで次のように書く。

@hoge = Hoge.first
render json: @hoge

結果

結果のjsonが以下のようになっている。

{
  id: 1,
  hogehoge: 'hoge',
  fugas: [
    {
      id: 1,
      fugafuga: 'fuga'
      // ここに bars が入ってこない!
    }
  ]
}

対応方法

active_model_serializers 0.10より、 ネストされたリソースは自動的に展開されなくなったとのこと。
https://github.com/rails-api/active_model_serializers/issues/1077

renderに include というオプションを渡すと、入ってくるようになる。

@hoge = Hoge.first
render json: @hoge, include: { fugas: [:bars] }

結果

{
  id: 1,
  hogehoge: 'hoge',
  fugas: [
    {
      id: 1,
      fugafuga: 'fuga',
      bars: [ // 入ってきた
        {
          id: 1,
          barbar: 'bar'
        }
      ]
    }
  ]
}

ActiveRecordに対するincludes/preloadと同じような形式で渡すことができる。

※参考:公式ドキュメント https://github.com/rails-api/active_model_serializers/blob/0-10-stable/docs/general/adapters.md#include-option

落穂拾い

デバッグ

render でやり続けてるとデバッグが効率わるい。もう少しローレベルなAPIを使ってデバッグする。

ActiveModelSerializers::SerializableResource.new(Hoge.first, include: { fugas: :bars }).as_json

詳細このへん

キー名を変えているときは、変えたあとのキー名で指定する

シリアライザでキー名を変えることができる。こんなふうに

class HogeSerializer < ActiveModel::Serializer
  attributes :id, :hogehoge
  has_many :fugas, key: :foos
end

この場合は、変えたあとのキー名 foos を指定する。

render json: @hoge, include: { foos: [:bars] }

よくよく考えれば当然なんだけど、これにちょっとハマった。

98
68
6

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
68