#●書きたいこと
N+1問題の解消でよくモデル.includes(〜〜〜)
という形を使うけど、
(〜〜〜)部分の書き方がわからず調べたのでメモしておく。
#●前提
[Spree::OptionType]
↓ ↑
has_many ↓ ↑ belongs_to
↓ ↑
[Spree::ProductOptionType] ←中間テーブル
↑ ↓
has_many ↑ ↓ belongs_to
↑ ↓
[Spree::Product]
という関係のときに、
includesを使ってOptionTypeとProductをつなぐ場合を考える。
※つなぐといってもテーブル結合のことではない
#●表記の仕方
●その1●
Spree::OptionType.includes(:product)
→OptionTypeとProductがつながる
●その2●
これ、
モデル.includes(A: :B)
モデル.includes(A: [:B, :C])
の形でも表せる。
その場合、AがBをメソッドや関連などで持っていないといけない、つまり、
AのオブジェクトにおいてBの名前を使って何かしらを呼び出せるような形になっていないといけない
例えば上のコードは
Spree::OptionType.includes(product_option_types: :product)
とかける。
●前提に書いたけど、この場合、Aに相当するproduct_option_types
はBに対応するproduct
を
belongs_toの形で関連づけしており、Spree::ProductOptionType.first.product
の形で表せるため
このコードでかける。
★別例
Spree::Product.includes(master: [:default_price, :images])
これはSpree::Productが、master(Spree::Variantオブジェクトの1つ)が持っている
default_price
、images
というメソッド(この場合delegateだが)を持っているので、
このような書き方ができる。
※簡単に説明すると、Spree::ProductはSpree::Variantをvariantsという名前でhas_manyしている。
またSpree::Variantの中ではmasterというscopeがあり、これは
「Spree::Variantのレコードの中でこの条件を満たすものをmasterとします」という旨のscopeである。
default_price, imagesはSpree::Variantの中でdelegateされているので、
Spree::Product.first.variants.first.display_price
という形で使える。
(これだとN+1が発生しますが)
以上、備忘録〜(2記事目)