LoginSignup
3
9

More than 3 years have passed since last update.

ActiveModelSerializerでネストしたアソシエーションを出力する方法

Last updated at Posted at 2019-10-10

環境

  • Rails 5.2.3
  • ActiveModelSerializer 0.10.9

条件(モデル)

  • company has_many departments
  • department has_many employees

この条件下で、CompanySerializerEmployeeを出力したい (※デフォルトでは、1階層しか出力されない。つまり、この場合はDepartmentまで)。

class Company < ApplicationRecord
  has_many :departments
end

class Department < ApplicationRecord
  belongs_to :company
  has_many :employees
end

class Employee < ApplicationRecord
  belongs_to :department
end

Serializerを定義する方法

  • ネストしたアソシエーションを定義する方法に注意(以下のNOTE部分 = has_many :employees を定義する場所)。
class CompanySerializer < ActiveModel::Serializer
  attributes :id, :name, :tel

  has_many :departments

  class DepartmentSerializer < ActiveModel::Serializer
    attributes :id, :name, :code

    # NOTE: EmployeeSerializer 内で attributes を指定する必要がない (全ての属性を出力する) 場合は、
    #       ここに定義して良い。
    # has_many :employees

    class EmployeeSerializer < ActiveModel::Serializer
      attributes :id, :name, :role

    # NOTE: serializer: EmployeeSerializer を指定しないと、全ての属性が出力される。
    #       attributes で定義したものだけを出力したい場合は、serializer オプションを付ける必要がある。
    # NOTE: EmployeeSerializer クラスを定義する前に serializer: EmployeeSerializer を呼ぶと、
    #       以下のエラーが出る。
    #       よって、以下の has_many 行をここ (class EmployeeSerializer より後) に定義している。
    #   uninitialized constant CompanySerializer::DepartmentSerializer::EmployeeSerializer
    has_many :employees, serializer: EmployeeSerializer
  end
end

Serializerの実行方法

  • includeでアソシエーションを指定する。
  • includeを使う以外に、ActiveModelSerializers.config.default_includes = '**'として、デフォルトの挙動を変えることも可能。デフォルトは'*'で、1階層しか含まれない (ドキュメントへのリンク)。

controllerの中でrenderする場合

# 単数 (company) の場合
render json: @company, include: { departments: [:employees] }
# 複数のアソシエーションをincludeする場合
render json: @company, include: [departments: [:employees], :something]
render json: @company, include: ['departments.employees', 'something'] }

# 複数 (companies) の場合 (arrayを出力したい場合)
render json: @companies, 
  each_serializer: CompanySerializer,
  include: { departments: [:employees] }

# '**' を使う。
render json: @company, include: '**'

controller以外でAMSを使う場合 (ActiveModelSerializers::SerializableResource を使う場合)

# 単数 (company) の場合
ActiveModelSerializers::SerializableResource.new(
   company, 
   serializer: CompanySerializer, 
   include: { departments: [:employees] }
).to_json

# 複数 (companies) の場合 (arrayを出力したい場合)
ActiveModelSerializers::SerializableResource.new(
  companies, 
  each_serializer: CompanySerializer, 
  include: { departments: [:employees] }
).to_json

# or

# '**' を指定することで、全てのネストされたリレーションを出力する。
# '*' の場合は、1階層のアソシエーションのみ (デフォルト)。
ActiveModelSerializers::SerializableResource.new(
   company, 
   serializer: CompanySerializer, 
   include: '**'
).to_json

参考 (オフィシャルドキュメント)

3
9
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
3
9