環境
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] }
よくよく考えれば当然なんだけど、これにちょっとハマった。