Я тоже столкнулся с этой проблемой. Проблема не в Rails, проблема определенно в MySQL:
Ваш SQL создаст следующую временную JOIN-таблицу (показаны только необходимые поля):
+-----------+-------------+---------+------------+
| things.id | things.name | tags.id | tags.name |
+-----------+-------------+---------+------------+
| 1 | ... | 1 | test_tag_1 |
+-----------+-------------+---------+------------+
| 1 | ... | 2 | test_tag_2 |
+-----------+-------------+---------+------------+
Таким образом, вместо объединения всех Tag
с одной конкретной Thing
, она генерирует одну строку для каждой комбинации Tag
- Thing
(Если вы не верите, просто запустите COUNT(*)
для этого оператора SQL) ,
Проблема в том, что ваши критерии запроса выглядят так: WHERE (tags.name = 'test_tag_1') AND (tags.name = 'test_tag_2')
, который будет проверяться по каждой из этих строк и никогда не будет истинным. tags.name
не может быть равным test_tag_1
и test_tag_2
одновременно!
Стандартным решением SQL является использование оператора SQL INTERSECT
... но, к сожалению, не с MySQL.
Лучшее решение - запустить Thing.withtag_search
для каждого из ваших тегов, собрать возвращаемые объекты и выбрать только объекты, включенные в каждый из результатов, например:
%w[test_tag_1 test_tag_2].collect do |tag|
Thing.withtag_search(tag)
end.inject(&:&)
Если вы хотите получить это как ActiveRecord
отношение, вы, вероятно, можете сделать это так:
ids = %w[test_tag_1 test_tag_2].collect do |tag|
Thing.withtag_search(tag).collect(&:id)
end.inject(&:&)
Things.where(:id => ids)
Другое решение (которое я использую) заключается в кэшировании тегов в таблице Thing
и выполнении в ней логического поиска MySQL. Я дам вам более подробную информацию об этом решении, если вы хотите.
В любом случае, я надеюсь, что это поможет вам. :)