eager loadingする時に参照先のテーブルが持ってる外部テーブルまで参照する

環境

ruby 2.4.2
rails 5.1.4

やりたいこと

eager loadingする際に、参照先テーブルが持ってる外部テーブルまでloadingしたい。
ということがあったので、備忘録も兼ねて紹介したと思います。

# => : 参照先とする
A => B
B => C

となっていた時に、AがBを通してCまでloadingするということです。

例えば下記のような3つのmodelがあり、Prefectureテーブル(A)からCountryテーブル(B)を通して、Continent(C)テーブルをloadingします。

class Prefecture < ApplicationRecord
  belongs_to :country
end

class Country < ApplicationRecord
  belongs_to :continent
end

class Continent < ApplicationRecord
  has_many :countries
end

やりかた

このように、includeするcounrty(B)のシンボルに、continent(C)をネストする形で渡してあげると良いです。

Prefectures_controller.tb
class PrefecturesController < ApplicationController
  @prefectures = Prefecture.all.includes(country: :continent)
end

ちなみにもし、counrty(B)がcontinentの他に、prefecture以外にLeaguesという外部テーブルとも関連付けが合って、それも参照がしたい場合、このようにしてあげる。

class Country < ApplicationRecord
  belongs_to :continent
  belongs_to :league
end

class PrefecturesController < ApplicationController
  @prefectures = Prefecture.all.includes(country: [:continent, :league])
end

おまけ

デメテルの法則では、「オブジェクトAは別のオブジェクトBのサービスを要求してもよい(メソッドを呼び出してもよい)が、オブジェクトAがオブジェクトBを「経由して」さらに別のオブジェクトCのサービスを要求してはならない。」ということが言われており、今回のケースに当てはまってしまっています。

しかし個人的には、今回のケースのオブジェクトA(Prefecture)が要求したオブジェクトC(Continent)のサービスは、オブジェクトCの値だったので、そんなに問題ないかなという認識です。

もしこれが、continent_modelに定義したメソッドの呼び出しなどになるとデメテルの法則で言われているように、保守が辛くなってしまうので気をつけたいですね。

デメテルの法則に関してはこちらの記事がわかりやすいです。
http://ruby-rails.hatenadiary.com/entry/20150922/1442923521

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.