Help us understand the problem. What is going on with this article?

関連する ActiveModel::Serializer を切り替える

はじめに

  • Associations において利用する Serializer を切り替えました
  • AMS で該当する機能は見つからなかったので素朴に実現しました

目次

  • はじめに
  • TL;DR
  • 環境
  • 構成
    • Model
    • API
  • やりたいこと
  • 実現方法
    • Controller
    • Serializer
  • まとめ
  • 参考

TL;DR

  • Rendering の際に options を渡す
reservations_controller.rb
  render json: reservation,
          include: '**', restaurant_type: :detail
  • Serializer の initialize で options を受け取る
reservation_serializer.rb
  def initialize(object, options = {})
    super
    @restaurant_type = options[:restaurant_type]
  • options の値によって 関連先で利用する Serializer を切り替える
reservation_serializer.rb
  attributes :id, :restaurant

  def restaurant
    serializer = case @restaurant_type
                  when :base then RestaurantSerializer
                  when :detail then RestaurantDetailSerializer
                  else RestaurantSerializer
                  end

    serializer.new(object.restaurant, @options)

環境

- ruby: 2.6.2
- rails: 5.2.3
- active_model_serializers: 0.10.9 

構成

Model

app/models/restaurant.rb
# == Schema Information
#
# Table name: restaurants
#
#  id                   :bigint(8)        not null, primary key
#  name                 :string           not null
#  phone                :string           not null
#  address              :string           not null

class Restaurant < ApplicationRecord
  has_many :reservations
app/models/reservation.rb
# == Schema Information
#
# Table name: reservations
#
#  id                   :bigint(8)        not null, primary key
#  restaurant_id        :bigint(8)        not null

class Reservation < ApplicationRecord
  belongs_to :restaurant

API

reservations_list.json
{
  "reservations": [
    {
      "id": 42,
      "restaurant": {
        "id": 42,
        "name": "Domino's Pizza"
      }
    }
  ]
}
reservation_detail.json
{
  "reservation": {
    "id": 42,
    "restaurant": {
      "id": 42,
      "name": "Domino's Pizza",
      "phone": "03-1234-5678",
      "address": "東京都XXXXXX"
    }
  }
}

やりたいこと

  • Reservations List API では restaurant の id, name のみを含める
  • Reservation Detail API では restaurant の id, name, phone, address を含める

実現方法

Controller

  • restaurant_type を Serializers に渡す
reservations_controller.rb
module API
  class ReservationsController < API::ApplicationController
    def index
      reservations = Reservation.all
      render json: reservations,
              include: '**', restaurant_type: :base
    end

    def show
      reservation = Reservation.find(params[:id])
      render json: reservation,
              include: '**', restaurant_type: :detail
    end
  end
end

Serializers

  • initialize で options[:restaurant_type] を受け取る
  • options[:restaurant_type] の値によって, Serializer を切り替える
  • @options を 渡すことで, options や scope を 引き継ぐ
reservation_serializer.rb
class ReservationSerializer < ActiveModel::Serializer
  attributes :id, :restaurant

  def initialize(object, options = {})
    super
    @options = options
    @restaurant_type = options[:restaurant_type]
  end

  def restaurant
    serializer = case @restaurant_type
                  when :base then RestaurantSerializer
                  when :detail then RestaurantDetailSerializer
                  else RestaurantSerializer
                  end

    serializer.new(object.restaurant, @options)
  end
end
restaurant_serializer.rb
class RestaurantSerializer < ActiveModel::Serializer
  attributes :id, :name
end
restaurant_detail_serializer.rb
class RestaurantDetailSerializer < RestaurantSerializer
  attributes :address, :phone
end

まとめ

  • 今回は牧歌的な方法で切り替えました
  • 良い方法があれば教えてください :bow:

参考

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした