状況
- blogとtagsがblog_tagsを中間テーブルとして多対多の状況になっている。
- N+1問題を解決すルため、includesを使う
Blog.includes(:tags).each { |blog| p blog.tags.map(&:name) }
SELECT "blogs".* FROM "blogs"
SELECT "blog_tags".* FROM "blog_tags" WHERE "blog_tags"."blog_id" IN (`取得したblogsのID`)
SELECT "tags".* FROM "tags" WHERE "tags"."id" IN (`取得したblog_tagsのid`)
やりたいこと
includesでtagsをキャッシュする際にカラムを指定したい
SELECT "tags".* FROM "tags" WHERE "tags"."id" IN (`取得したblog_tagsのid`)
↓
SELECT "tags".name FROM "tags" WHERE "tags"."id" IN (`取得したblog_tagsのid`)
解決策
下記のように、モデルのアソシエーション定義の部分に、lambda関数を渡してあげる。
こうすると、アソシエーションを使う際にlambda関数が呼ばれる
app/models/blog.rb
class Blog < ApplicationRecord
has_many :blog_tags, dependent: :destroy
has_many :tags, ->{ select('tags.name')}, through: :blog_tags
end
参考