has_many(through)アソシエーションでの検索

Activerecordでリレーションテーブルを介してテーブルを関連づけ、関連元のテーブルを検索するさいに関連付けられた先のテーブル(=has_manyで指定するテーブル)を検索条件に加える仕方を調べたのでメモリます。

今回の例は商品(products)とその商品を検索するためのキーワード(keywords)とそれの関連づけテーブル(product_keywords)の3つを使いました。
それで目的となるのは関連づけられた先のキーワードで商品を検索するということです。

アソシエーション

以下のように関連づけ元のモデルであるProductから多の2テーブルに対してhas_manyアソシエーションを指定します。
keywordsに対しては関連付けテーブル「keyword_products」を介して(through)という指定になります。

class Product < ActiveRecord::Base
  has_many :keyword_products
  has_many :keywords, :through => :keyword_products
...

検索

上記のようにアソシエーション指定した上で、:includeオプションに関連先のテーブル(「keywords」),:conditionsに関連先のテーブル(「keywords」)のカラムを指定してfindメソッドを呼び出します。

     products = Product.find(:all,
      :include => [:keywords],
      :conditions => ["keywords.word = ?", "beatles"] )

これで以下のような外部結合したSQLが実行されます。

SELECT `products`.`id` AS t0_r0, `products`.`name` AS t0_r3,  ....
LEFT OUTER JOIN `keyword_products` ON (`products`.`id` = `keyword_products`.`product_id`)
LEFT OUTER JOIN `keywords` ON (`keywords`.`id` = `keyword_products`.`keyword_id`)
WHERE (keywords.word = 'beatles')

これで、findメソッドの返値として検索結果分のProductモデルを含む、Arrayが返ってきます。