これは私が自分で見つけた解決策です。変更されていない場合、Rails 3 (またはそれ以降) でのみ機能します。
タグモデルでは:
scope :find_by_names, lambda { |names|
unless names.empty?
where("tags.name IN (#{Array.new(names.length, "?").join(",")})", *names)
else
where("false")
end
}
質問モデルでは:
scope :tagged_with, lambda { |tag_names|
unless tag_names.blank?
joins(:question_tags).
where("questions.id = question_tags.question_id").
joins(:tags).where("tags.id = question_tags.tag_id").
group("questions.id").
having("count(questions.id) = ?", tag_names.count) & Tag.find_by_names(tag_names)
else
scoped
end
}
は、2 つの& Tag.find_by_names(tag_names)
スコープを組み合わせて、結合tags
が実際にはスコープ モデルの結合になるようにします。
[アップデート]
私のsql-fuは少し改善されたので、純粋なSQLソリューションも提供したいと思いました:
SELECT q.*
FROM (
SELECT DISTINCT q.*
FROM `questions` q
JOIN question_tags qt
ON qt.question_id = q.id
JOIN tags t
ON t.id = qt.tag_id
WHERE t.name = 'dogs'
) AS q
JOIN question_tags qt
ON qt.question_id = q.id
JOIN tags t
ON t.id = qt.tag_id
WHERE t.name = 'cats'
これにより、'cats' と 'dogs' の両方でタグ付けされたすべての質問が検索されます。アイデアは、フィルターしたいタグごとにネストされたサブクエリを持つことです。
これには他にもいくつかの方法があります。FROM
句の代わりに句にサブクエリを含めることで違いが生じるかどうかはわかりませんWHERE
。任意の洞察をいただければ幸いです。