I've got two models: Item
and Tag
. Both have a name attribute. I want to find items tagged with several tags.
class Item < ActiveRecord::Base
has_many :tags
validates_presence_of :name
end
class Tag < ActiveRecord::Base
belongs_to :item
validates_presence_of :name
end
Given a list of tag ids, I can easily enough get the list of items tagged with one tag or the other:
# Find the items tagged with one or more of the tags on tag_ids
Item.all(:conditions => ['tags.id in (?)', tag_ids], :joins => :tags)
If tag_ids
is {1,4}
, then I get all pictures tagged with 1, or 4, or both.
I want to know now how to get the pictures that are tagged with both - 1 AND 4.
I can't even imagine the SQL that is needed here.
You can solve this by grouping the results and checking the count:
Item.all(
:conditions => ['tags.id IN (?)', tag_ids],
:joins => :tags,
:group => 'items.id',
:having => ['COUNT(*) >= ?', tag_ids.length]
)
Little update : Today, we can use (inspired by elektronaut) :
Item.joins(:tags).where("tags.label in (?)", tags).group('items.id').having("COUNT(*) >= ?", tags.size)
It is not very different, by it works well here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With