🐰

Rails で 複数の Serializer を組み合わせる

2024/04/18に公開

Rails で API を開発しています。
あるキーの値があるモデルを Serialize した結果であるようなレスポンスを返したいときの Serializer の実装につまづいたので、解決策を備忘録としてまとめます。

結論

  • ActiveModelSerializers::SerializableResource.new を使う

やりたいことと前提

user_posts_controller.rb の show メソッドで、上述したようなレスポンスを返したい。

posts キーの中身は Post モデルが PostsSerializer によって Serialize された配列を返したい。
また、すでに PostsSerializer は実装されており、別の Controller で使用されている。
posts キー以外は User モデルの attribute となっており、posts と同一の階層で返したい[1]
このとき、User を Serialize し、さらに Posts も Serialize する必要があります。
User モデルと Post モデルは同一階層に位置しているため、Serializer をネストする必要があり、その方法がわからず困ってました。

{
    "name": "なまえ", 
    "age": 24,
    "address": "----",
    "posts": [
        // Post モデルが、PostsSerializer によって Serialize されたやつの配列
        // (省略)
    ]
}

解決策

Serializer 内で、Serializer を呼び出せるのでそのようなメソッドを定義する

user_posts_controller.rb

def show
# データを取得する処理は省略する

results = { user: user, posts: posts }

render json: results, serializer: UserPostsSerializer
end

user_posts_serializer.rb

class UserPostsSerializer < ActiveModel::Serializer
  attribute :name, :age, :address
  attribute :posts

  def name
    object[:user][:name]
  end

  def age
    object[:user][:age]
  end

  def address
    object[:user][:address]
  end

  def posts
    ActiveModelSerializers::SerializableResource.new(
      object[:posts], each_serializer: PostsSerializer
    ).as_json
  end
end

さいごに

他によりよい方法があればご指摘いただけますと幸いです。

脚注
  1. user キーを使ってネストさせた方がいいと思いますが、Serializer の数が増えてしまうので、簡略化のために同一階層としています。 ↩︎

Discussion