delhi09の勉強日記

技術トピック専用のブログです。自分用のメモ書きの投稿が多いです。あくまで「勉強日記」なので記事の内容は鵜呑みにしないでください。

Active Recordのmergeメソッドで結合先のモデルのscopeを条件に含む検索を実現する

前提として、以下のようにscopeが定義されたTagモデルを定義します。

class Tag < ApplicationRecord
  has_and_belongs_to_many :restaurants
  scope :south_india, -> { where(name: "南インド") }
end

Tag.south_indiaとすると以下のSQLが発行されます。

SELECT "tags".* FROM "tags" WHERE "tags"."name" = '南インド';

Tagモデルと多対多の関係にあるRestaurantモデルからTagモデルのscopeを使って絞り込むSQLを発行したいです。

その場合はmergeメソッドが使えます。

Restaurant.joins(:tags).merge(Tag.south_india)

以下のようなSQLが発行されます。

SELECT "restaurants".*
FROM "restaurants"
INNER JOIN "restaurants_tags" ON "restaurants_tags"."restaurant_id" = "restaurants"."id"
INNER JOIN "tags" ON "tags"."id" = "restaurants_tags"."tag_id"
WHERE "tags"."name" = '南インド';

Railsガイドにも「高度な条件指定や既存の名前付きスコープの再利用を行いたい場合は、mergeが利用できるでしょう。」とあります。

railsguides.jp

複雑なクエリを直観的に扱えて便利だなという印象です。