8
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Posted at

はじめに

  • 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:

参考

8
5
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
8
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?