For the purpose of this question, let’s assume I’m building Stack Overflow.
I’ve got a many-to-many relationship via an association table for Posts and Tags, and I’d like to search for posts that contain multiple tags.
I can search for posts that contain a single tag like this:
scope :has_tag, lambda { |tag| includes(:tags).where("lower(tags.name) = ?", tag.downcase) }
Post.has_tag("Python")
For searching for multiple tags, I’ve tried building up a query using a loop:
def self.has_tags(tags)
query = includes(:tags)
tags.each do |tag|
query = query.where("lower(tags.name) = ?", tag)
end
return query
end
This results in the query ... WHERE (lower(tags.name) = 'tag1') AND (lower(tags.name) = 'tag2'), which doesn’t match anything.
I’ve also tried using .where('tags.name IN (?)', tags), but I think that matches any post that contains one of the tags instead of posts that contain all the tags.
Now I’m thinking that perhaps I should use the ID of the tags, but that sounds like it could result in multiple queries. Is this inefficient?
... WHERE tag_id IN (SELECT id FROM tag WHERE name IN ('tag1','tag2'))
What’s the best way to search for multiple tags?
(I’d prefer to understand the syntax and do it manually rather than using a gem, since I’m new to Rails.)
I ended up using the following: