在Rails中反转has_many

时间:2009-03-31 07:02:29

标签: ruby-on-rails reverse has-many

假设我有模型:用户和项目以及它们之间的多对多关系。如何获得具有完全(不再)具有已定义属性的项目的用户,即具有颜色= ['red','black']的项目的用户。

当然我可以这样做:

User.all :joins => [:items, :items], :conditions => {:"items.color" => "red", :"items_users.color" => 'black'}

但是对于更多属性来说,这将非常麻烦。 我也可以这样做:

User.all(:conditions => ["items.color in (?), ['red', 'black']], :include => :items)

但是这个用户还会返回颜色为[''red','black','blue','etc']

的项目的用户

所以唯一的解决方案是获取所有并使用ruby语法排序?如何在一个SQL查询或Rails AR语法中执行此操作?

1 个答案:

答案 0 :(得分:1)

在我看来,优化程序员时间和可读性的方法:

#get all users who have items which are both red and black but no other colors
candidate_users = User.all(:include => :items)
candidate_users.reject! do |candidate| 
  candidate.items.map {|item| item.color}.sort != ['black', 'red']
end

如果您希望在那里循环使用公制卡车的用户,那么您需要对其进行SQL编写。警告:SQL不是我的包,宝贝:使用前测试。

select users.*, items.* FROM users 
  INNER JOIN items_users ON (items_users.user_id = users.id) 
  INNER JOIN items ON (items_users.item_id = items.id) 
    GROUP BY users.id HAVING COUNT(DISTINCT items.color) = 2 

我认为邪恶的混乱:

1)抓住每个用户/项目组合    2)向具有2种不同颜色项目的用户进行Winnows

这意味着你需要:

candidate_users.reject! do |candidate| 
  candidate.items.map {|item| item.color}.sort != ['black', 'red']
end

你可以完全消除对红宝石的需求,但SQL会有七种难看的味道。 (Cross加入,哦,我的...)