2012-08-10 52 views
1

我有以下结构项目的一个简单的标签系统:多用连接和那里的条件

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 

我想一个scope添加到Item类能够得到的所有项目一组给定的标签(包括中设定的所有标签)

所以我尝试了以下范围:

scope :tag_context, lambda { |context| (context.empty? ? all : 
     joins(:taggings).where(:taggings => {tag_id => context.collect(&:id)}) 
     ) 
    } 

其中contextArrayTag对象。

的一点是,此范围内产生的SQL语句:

SELECT items.* FROM items INNER JOIN taggings ON taggings.item_id = items.id 
          WHERE taggings.tag_id IN (1,2) 

假设context包含标签1和2

我想获得由标签1和标签2标签的物品。 所以我认为,这样的:

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 

我应该如何继续它在Rails范围翻译? 我需要一个范围,以便能够链接Item类的各种范围。

感谢您的帮助!

回答

1

您可以尝试建立动态范围是这样的(你并不需要一个.empty?检查与inject):

scope :tag_context, lambda { |context| 
     context.collect(&:id).inject(self) do |m, id| 
     m.joins("INNER JOIN taggings as t#{id} ON t#{id}.item_id = items.id"). 
     where("t#{id}.tag_id = ?", id) 
     end 
} 
+0

太好了!谢谢!我尝试了类似的东西,但没有范围。使用'inject'方法,它很简单并且可行! – microcosme 2012-08-12 14:27:58