Перевернутое has_many в Rails - PullRequest
3 голосов
/ 31 марта 2009

Допустим, у меня есть модели: Пользователь и Предмет и отношение многие-ко-многим между ними. Как получить пользователей, которые имеют точно (не более) элементов с определенными атрибутами, то есть пользователей, которые имеют элементы с цветами = ['red', 'black'].

Конечно, я могу сделать что-то вроде этого:

User.all :joins => [:items, :items], :conditions => {:"items.color" => "red", :"items_users.color" => 'black'}

Но для большего количества атрибутов это будет довольно громоздко. Я также могу сделать:

User.all(:conditions => ["items.color in (?), ['red', 'black']], :include => :items)

Но этот возвращает также пользователей с элементами, имеющими цвета = ['red', 'black', 'blue', 'etc']

Таким образом, единственное решение - получить все и отсортировать по синтаксису ruby? Как это сделать в одном запросе SQL или в синтаксисе Rails AR?

1 Ответ

1 голос
/ 31 марта 2009

Способ, который оптимизирует время программиста и читабельность, на мой взгляд:

#get all users who have items which are both red and black but no other colors
candidate_users = User.all(:include => :items)
candidate_users.reject! do |candidate| 
  candidate.items.map {|item| item.color}.sort != ['black', 'red']
end

Если вы ожидаете, что там будет проходить цикл метрической загрузки пользователей, вам нужно будет выполнить SQL-запрос. Предупреждение: SQL не моя сумка, детка: тест перед использованием.

select users.*, items.* FROM users 
  INNER JOIN items_users ON (items_users.user_id = users.id) 
  INNER JOIN items ON (items_users.item_id = items.id) 
    GROUP BY users.id HAVING COUNT(DISTINCT items.color) = 2 

Что я думаю, что делает этот злой беспорядок:

1) Захватывает каждую комбинацию пользователя / предмета 2) Отвечает пользователям, у которых есть предметы ровно 2 разных цветов

Что означает, что вам нужно:

candidate_users.reject! do |candidate| 
  candidate.items.map {|item| item.color}.sort != ['black', 'red']
end

Вероятно, вы можете полностью исключить необходимость использования рубина, но SQL получит семь уродливых разновидностей. (Крест присоединяется, о боже ...)

...