Rails APIのJbuilderで親・子・孫をアソシエーションで取得

Rails6 APIモードで、親・子・孫のリレーション関係をアソシエーション設定したあとに、Jbuilderのviewsで取得する方法。

設定

api/app/models/agenda_group.rb

class AgendaGroup < ApplicationRecord
  belongs_to :user
  has_many :agenda_items, -> { order('order_number') }, dependent: :destroy

  scope :ordered, -> {
    order('name')
  }
end

api/app/controllers/v1/agenda_groups_controller.rb

  def show_relations
    @agenda_groups = AgendaGroup.ordered
    render 'index', format: :json, handlers: 'jbuilder'
  end

api/app/views/v1/agenda_groups/index.json.jbuilder

#--- (親モデル)agenda_groups ---
json.array! @agenda_groups do |ag|
  json.extract! ag,
    :id,
    :name,
    :created_at,
    :updated_at

  #--- (子モデル)agenda_items ---
  json.agenda_items do # JSONのグループ
    json.array! ag.agenda_items do |ai| # 配列をループで取得
      json.extract! ai, # 指定した以下のカラムを出力
        :id,
        :name,
        :order_number,
        :indent_level,
        :created_at,
        :updated_at

      #--- (孫モデル)agenda_details ---
      json.agenda_details do
        json.array! ai.agenda_details do |ad|
          json.extract! ad,
            :id,
            :body,
            :created_at,
            :updated_at
        end
      end
      #--- /agenda_details ---

    end
  end
  #--- /agenda_items ---

end
#--- /agenda_groups ---

出力結果

[
    {
        "id": 86,
        "name": "2021/09/05 16:29の登録",
        "created_at": "2021-09-05T07:30:47.926Z",
        "updated_at": "2021-09-05T07:30:47.926Z",
        "agenda_items": []
    },
    {
        "id": 64,
        "name": "test",
        "created_at": "2021-09-05T07:05:15.065Z",
        "updated_at": "2021-09-05T07:05:51.025Z",
        "agenda_items": []
    },
    {
        "id": 3,
        "name": "Business Analysis Agenda",
        "created_at": "2021-08-14T07:04:29.496Z",
        "updated_at": "2021-08-14T07:04:29.496Z",
        "agenda_items": []
    },
    {
        "id": 1,
        "name": "RDD Agenda",
        "created_at": "2021-08-14T05:40:54.293Z",
        "updated_at": "2021-08-14T05:40:54.293Z",
        "agenda_items": [
            {
                "id": 1,
                "name": "Overview",
                "order_number": 1,
                "indent_level": null,
                "created_at": "2021-08-14T05:42:50.929Z",
                "updated_at": "2021-08-14T05:42:50.929Z",
                "agenda_details": [
                    {
                        "id": 1,
                        "body": "This document aims to give a detailed description on how the applications that will be implemented are designed."
                    },
                    {
                        "id": 12,
                        "body": "The Project will be divided into 6 phases."
                    },
                    {
                        "id": 5,
                        "body": "コレクションをインスタンスから取得できます。"
                    }
                ]
            },
            {
                "id": 9,
                "name": "Loadmap",
                "order_number": 2,
                "indent_level": 2,
                "created_at": "2021-09-05T07:21:23.096Z",
                "updated_at": "2021-09-15T10:50:29.379Z",
                "agenda_details": [
                    {
                        "id": 4,
                        "body": "The Project will be divided into 6 phases."
                    }
                ]
            },
            {
                "id": 10,
                "name": "Project Phases",
                "order_number": 2,
                "indent_level": null,
                "created_at": "2021-09-05T07:21:39.276Z",
                "updated_at": "2021-09-05T07:21:39.276Z",
                "agenda_details": []
            }
        ]
    },
    {
        "id": 63,
        "name": "RFP Agenda",
        "created_at": "2021-09-05T07:04:36.890Z",
        "updated_at": "2021-09-05T07:04:36.890Z",
        "agenda_items": []
    },
    {
        "id": 68,
        "name": "RFP Agenda",
        "created_at": "2021-09-05T07:19:15.892Z",
        "updated_at": "2021-09-05T07:19:15.892Z",
        "agenda_items": [
            {
                "id": 12,
                "name": "Project Phases",
                "order_number": 1,
                "indent_level": null,
                "created_at": "2021-09-05T07:27:39.135Z",
                "updated_at": "2021-09-05T07:27:39.135Z",
                "agenda_details": []
            },
            {
                "id": 13,
                "name": "Project Phases",
                "order_number": 1,
                "indent_level": 1,
                "created_at": "2021-09-15T11:01:24.145Z",
                "updated_at": "2021-09-15T11:01:24.145Z",
                "agenda_details": []
            },
            {
                "id": 11,
                "name": "Project Phases",
                "order_number": 3,
                "indent_level": null,
                "created_at": "2021-09-05T07:27:29.312Z",
                "updated_at": "2021-09-05T07:27:29.312Z",
                "agenda_details": []
            }
        ]
    },
    {
        "id": 4,
        "name": "Sample Agenda",
        "created_at": "2021-08-14T14:49:24.904Z",
        "updated_at": "2021-08-14T14:49:24.904Z",
        "agenda_items": []
    },
    {
        "id": 2,
        "name": "Sample Agenda",
        "created_at": "2021-08-14T07:04:11.558Z",
        "updated_at": "2021-08-14T07:04:11.558Z",
        "agenda_items": []
    },
    {
        "id": 9,
        "name": "Test Agenda",
        "created_at": "2021-08-14T14:56:24.066Z",
        "updated_at": "2021-08-14T14:56:24.066Z",
        "agenda_items": [
            {
                "id": 8,
                "name": "Sample Agenda Item",
                "order_number": 1,
                "indent_level": null,
                "created_at": "2021-08-15T14:56:33.134Z",
                "updated_at": "2021-08-15T14:56:33.134Z",
                "agenda_details": [
                    {
                        "id": 3,
                        "body": "1つのアカウントが1つのアカウント履歴に関連付けられる場合、以下のような感じになります。"
                    }
                ]
            }
        ]
    }
]