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

# 環境

- Rails 5.2.3
- ActiveModelSerializer 0.10.9

# 条件（モデル）

- `company` has_many `departments` 
- `department` has_many `employees` 

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

```ruby
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` を定義する場所）。

```ruby
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階層しか含まれない （[ドキュメントへのリンク](https://github.com/rails-api/active_model_serializers/blob/v0.10.6/docs/general/configuration_options.md#default_includes)）。

## controllerの中で`render`する場合

```ruby
# 単数 （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` を使う場合）

```ruby
# 単数 （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
```

- [AMSをController以外で使う方法](https://github.com/rails-api/active_model_serializers/blob/v0.10.6/docs/howto/outside_controller_use.md#using-activemodelserializers-outside-of-a-controller)

# 参考 （オフィシャルドキュメント）

- [includeオプションについて](https://github.com/rails-api/active_model_serializers/blob/v0.10.6/docs/general/adapters.md#include-option)