I have a simple tagging system of items with the following structure:
class Item < ActiveRecord::Base
has_many :taggings, :dependent => :destroy
has_many :tags, :through => :taggings
end
class Tagging < ActiveRecord::Base
belongs_to :tag
belongs_to :item
end
class Tag < ActiveRecord::Base
has_many :taggings, :dependent => :destroy
end
I’d like to add a scope to the Item class to be able to get all the items with a given set of tags (all tags in the set included)
So I tried the following scope:
scope :tag_context, lambda { |context| (context.empty? ? all :
joins(:taggings).where(:taggings => {tag_id => context.collect(&:id)})
)
}
where context is an Array of Tag objects.
The point is that this scope yield the following sql:
SELECT items.* FROM items INNER JOIN taggings ON taggings.item_id = items.id
WHERE taggings.tag_id IN (1,2)
assuming context contains tag 1 and 2.
I would like to get items that are tagged by tag 1 AND tag 2.
So I assume, something like:
SELECT items.* FROM items INNER JOIN taggings as t1 ON t1.item_id = items.id
INNER JOIN taggings as t2 ON t2.item_id = items.id
WHERE t1.tag_id = 1 AND t2.tag_id = 2
How should I proceed to translate it in a Rails scope?
I need a scope in order to be able to chain the various scopes on the Item class.
Thanks for your help!
You can try building the scope dynamically like this (and you don’t need an
.empty?check withinject):