Rails:Postgresql里面有多个连接条件(多态)

时间:2012-05-22 01:44:50

标签: ruby-on-rails ruby-on-rails-3 postgresql activerecord join

嗨,大家好,我的代码是:

class Tailor < ActiveRecord::Base
    has_many    :tailor_items
    has_many    :order_items

    [:collars, :sexes, :sleeves].each do |attribute|
        has_many    attribute, through: :tailor_items, source: :item, source_type: attribute.to_s.classify

    end
 end

class TailorItem < ActiveRecord::Base
  belongs_to        :tailor
  belongs_to        :item, polymorphic: true
end

class Collar < ActiveRecord::Base
end

我需要做的是: 对于给定的衬衫,我需要选择裁缝。衬衫可以有领子,男/女或某种类型的袖子。一些裁缝可以制作所有衣领但只有几个袖子,其他人只能制作男性用品等。 优先级对于此示例无关紧要。我的想法是我最终得到了1个裁缝。

我试过了:

tailors = Tailor.joins(:tailor_items).where("(item_id = ? and item_type = ?)",1,"Collar")
if tailors.count > 1
  tailors.where("(item_id = ? and item_type = ?)",2,"Sleeve")
  if tailors.count > 1
     # and so forth.
  end
end

但我从来没有回过头来。 如果我说:

Tailor.find(1).tailor_items 

我得到两个结果(简单的sudo代码)

<id: 1, item_type: "Collar"><id:2, item_type:"Sleeve"> 

和第二个裁缝:

Tailor.find(2).tailor_items 

我得到两个结果(简单的sudo代码)

<id: 1, item_type: "Collar"><id:3, item_type:"Sleeve"> 

但是当我尝试在查询中链接它们时它没有用... 即使我把它全部放在一个地方:

Tailor.where("(item_id = 1 and item_type = 'Collar') and (item_id = 2 and item_type = 'Sleeve')")

我仍然得到0结果。

Tailor.where("item_id = 1 and item_type = 'Collar'") returns: Tailor #1
Tailor.where("item_id = 2 and item_type = 'Sleeve'") returns: Tailor #1

但他们一起什么也没有回报。

Tailor Load (0.0ms) SELECT "tailors".* FROM "tailors" INNER
JOIN "tailor_items" ON "tailor_items"."tailor_id" = "tailors"."id" WHERE ((tailo
r_items.item_id = 1 and tailor_items.item_type = 'Collar') and (tailor_items.ite
m_id = 2 and tailor_items.item_type = 'Sleeve'))

我很困惑..

感谢您的帮助。

我跑: 赢得XP PostgreSQL的 Rails 3.2.2

PS:在多态连接之后,唯一缺少的就是XML。 :P否则它只是企业不够......

编辑: 实现Rob di Marcos范围,我得到了这个SQL:

SELECT "tailors".* FROM "tailors" WHERE 
(EXISTS(SELECT * FROM tailor_items WHERE tailor_items.item_id = 1 and tailor_items.item_type = 'Collar')) 
AND (exists(select * from tailor_items where tailor_items.item_id = 2 and tailor_items.item_type = 'Sleeve'))

返回 2裁缝而不是只裁缝1谁可以做两个(虽然裁缝2不能做袖#2)

1 个答案:

答案 0 :(得分:2)

问题是需要在两行上匹配的位置。我通常会使用子查询来测试它。像

这样的东西
Tailor.where("exists (select 'x' from tailor_items where 
         tailor_id = tailors.id and tailor_items.item_id = ? and 
         tailor_items.item_type=?)", 1, 'Collar').
       where("exists (select 'x' from tailor_items where 
         tailor_id = tailors.id and tailor_items.item_id = ? and 
         tailor_items.item_type=?)", 2, 'Sleeve')

在这个例子中,我为我正在寻找的每个裁缝项目都有一个子查询。我可以轻松地将它作为Tailor的范围,如:

class Tailor
  # ....
  scope :with_item, lambda{ |item_id, item_type | 
      where("exists (select 'x' from tailor_items where 
     tailor_id = tailors.id and tailor_items.item_id = ? and 
     tailor_items.item_type=?)", item_id, item_type)
     }

然后能够链接我的裁缝请求

Tailor.with_item(1, 'Collar').with_item(2, 'Sleeve')