найти сообщение, связанное с обеими двумя категориями в Rails 3 без специального SQL - PullRequest
2 голосов
/ 04 марта 2012

Я работаю над приложением Rails 3, которое (ради этого вопроса) Posts связано с несколькими Categories и наоборот через has_and_belongs_to_many ассоциации:

Post < ActiveRecord::Base
  has_and_belongs_to_many :categories
end

Category < ActiveRecord::Base
  has_and_belongs_to_many :posts
end

Iя пытаюсь выяснить, как написать ActiveRecord (или ARel) искатель, который извлекает все Posts, где каждый сообщение связано с оба из двух Categories.Я понимаю SQL, который в конечном итоге пытаюсь сгенерировать (два ВНУТРЕННИХ СОЕДИНЕНИЯ с псевдонимами, чтобы можно было различить каждый из них для сопоставления на каждом из двух Categories), но до сих пор я не нашел способ создатьзапрос, не прибегая к необработанным битам SQL.

Причина, по которой отказ от пользовательского SQL так важен в этом случае, заключается в том, что код, который я пишу, является общим и в значительной степени управляемым данными, и его необходимо смешивать с другими фильтрами(и сортировка) квалификаторов в запросе для Post объектов, поэтому я не могу просто жестко закодировать ни вызовы методов на Post (например, для доступа к коллекции Categories), ни пользовательский SQL, который может плохо сочетаться сSQL, генерируемый другими фильтрами.

Я открыт для перехода на использование модели соединения (has_many :through), если это как-то облегчает задачу, или даже на просмотр других опций ORM (DataMapper, Mongoid и т. Д.).), но это кажется огромным изменением только для того, чтобы заставить что-то настолько простое работать.

Я ошеломлен тем, что в ActiveRecord / ARel это не проще / более очевидноМожет быть, я просто не знаю магические ключевые слова для поиска, чтобы найти ответ.Документация для ARel также удивительно тонкая, поэтому я в растерянности.Любая помощь будет высоко ценится!

1 Ответ

1 голос
/ 05 марта 2012

После довольно большого количества поисков в Google я нашел эти две статьи (с 2006 года!), Которые в итоге привели меня к правильному ответу в ActiveRecord / ARel:

http://blog.hasmanythrough.com/2006/6/12/when-associations-arent-enough

http://blog.hasmanythrough.com/2006/6/12/when-associations-arent-enough-part-2

(почти) SQL-свободный код, который производит то, что я ищу, довольно умно использует операторы GROUP BY и HAVING в SQL:

Post.joins(:categories).where("categories.name" => ['catA','catB']).group('posts.id').having('COUNT(posts.id) = 2')

По сути, он находит все Posts, связанные с любым данного Categories (включая дубликаты, если, как мы надеемся, есть Posts, которые соответствуют нескольким Categories), группы, которые список в поле id на Post, затем обрезает результаты до тех групп, которые имеют ровно столько совпадений, сколько мы хотим.

Я не пробовал смешивать этот код с моими фильтрами в других полях Post, но я почти уверен, что он будет работать.

...