Для того, чтобы форумы имели все теги форумов в массиве @tags
, в следующем порядке.Я делаю предположение, что forum
не будет иметь один и тот же forum_tag
более одного раза.
@forums = Forum.joins(:forum_tags).where(:forum_tags => {:name => @tags}).group("forums.id").having(['COUNT(*) = ?', @tags.length]).includes(:forum_tags).all
Это создаст запрос SQL, подобный следующему:
@tags = ['foo', 'bar']
SELECT forums.id, forum_tags.id FROM forums
LEFT OUTER JOIN forum_tags_forums on forum_tags_forums.forum_id = forums.id
LEFT OUTER JOIN forum_tags ON forum_tags.id = forum_tags_forums.forum_tag_id
WHERE forum_tags.name IN ('foo', 'bar')
GROUP BY forums.id
HAVING COUNT(*) = 2;
Это сгруппирует все строки в объединяемой таблице по форумам, которые соответствуют заданным тегам.Если функция COUNT
имеет значение общего количества тегов, которые вы ищете (и нет дублирующихся пар forum
/ forum_tag
), тогда форум должен содержать все теги.
Чтобы получить оставшиеся теги (вопрос задан в комментариях):
forum_tags = ForumTag.where(:name => @tags)
@forums_with_leftovers = Forum.select("forums.*, GROUP_CONCAT(forum_tags.name) AS leftover_tags").joins(:forum_tags).where(['forums.id IN (?) AND NOT forum_tags.id IN (?)', @forums, forum_tags]).group("forums.id").all
Каждый Forum
объект в @forums_with_leftovers
будет иметь дополнительный атрибут leftover_tags
, который содержит разделенный запятыми список тегов в каждомобъект форума, который не находится в исходной переменной @tags
.