Die has_and_belongs_to_many Assoziation ist in ihrer klaren aber mächtigen Funktion eines der Highlights von Rails und ActiveRecord im besonderen. Wie man aber eine Abfrage durch die Auflösungstabelle hindurch eingrenzt ist nicht sofort ersichtlich. Hier also ein Beispiel dafür.
Die beiden Modelle Category und Product sind über has_and_belongs_to_many miteinander verbunden.
class Category < ActiveRecord::Base
has_and_belongs_to_many :products, :order => "title"
end
class Product < ActiveRecord::Base
has_and_belongs_to_many :categories
end
Die Auflösungstabelle folgt den Rails Konventionen:
CREATE TABLE `categories_products` (
`category_id` int(11) default NULL,
`product_id` int(11) default NULL,
`created_at` datetime default NULL,
`updated_at` datetime default NULL
) ENGINE=InnoDB;
Möchte man nun ein alle Produkte, aber nicht die der Kategorie 48 nd 51 holen muss man der find Methode einen angepassten :conditions Parameter und eine :include Anweisung mitgeben
@products = Product.find( :all,
:conditions => ['products.title like ? and (categories_products.category_id != 48 and categories_products.category_id != 51)', "#{params[:phrase]}%"],
:include => [:categories],
:limit => 8)
Dieser Aufruf holt alle Produkte deren title Feld mit params[:phrase] beginnt und die nicht zu den kategorien 48 und 51 gehören. Die Query die ActiveRecord dafür im Hintergrund abfeuert sieht so aus:
SELECT DISTINCT `products`.id FROM `products` LEFT OUTER JOIN `categories_products` ON `categories_products`.product_id = `products`.id LEFT OUTER JOIN `categories` ON `categories`.id = `categories_products`.category_id WHERE (products.title like 'ct%' and (categories_products.category_id != 48 and categories_products.category_id != 51)) LIMIT 8