Способ, который оптимизирует время программиста и читабельность, на мой взгляд:
#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 получит семь уродливых разновидностей. (Крест присоединяется, о боже ...)