与自身的可选has_one关联的范围

时间:2013-12-21 08:16:50

标签: ruby-on-rails postgresql activerecord ruby-on-rails-3.2

我有一个模型缩进。我正在使用STI。缩进可以是两种类型的销售和购买。在购买类中,我使用可选的has_one关联。

class Purchase < Indent
    has_one :sale , :class_name => 'Sale', :foreign_key => 'linked_indent_id'
    # Make it work.  
    scope :unsold, lambda {includes(:sale).where('id not in (select distinct linked_indent_id from indents)')}
end

class Sale < Indent
   belongs_to :purchase , :class_name => 'Purchase', :foreign_key => 'linked_indent_id'
end

我只需要购买类的范围,我可以使用该范围找到所有未与销售相关联的购买。

我使用Rails 3.2和Postgres作为数据库。

更新

生成的查询如下。

 SELECT "indents".* FROM "indents" WHERE "indents"."type" IN ('Purchase') AND 
 (id not in (select distinct linked_indent_id from indents)) ORDER BY indent_date DESC

以下部分查询工作正常。

=# select distinct linked_indent_id from indents;

 linked_indent_id 
 ------------------

        15013
        15019
       (3 rows)

这也很好。

SELECT "indents".* FROM "indents" WHERE "indents"."type" IN ('Purchase') AND
(id not in (15013, 15019)) ORDER BY indent_date DESC

在将这两部分查询联系起来时,我缺少什么?

2 个答案:

答案 0 :(得分:1)

我首先对术语purchasesale感到困惑。但是我相信你的更新有助于我更多地理解这个问题。

所以我所理解的是,未售出的是购买减去销售额。以下应该给你那个清单:

scope :unsold, lambda {includes(:sale).select { |p| !p.sale.present? } }

更新:

简要说明这里发生的事情:

范围并不真正完成数据库中的所有工作。它会对所有购买进行SQL选择,包括首先加入的销售。这将为您提供purchases表中的所有记录。然后,此范围将回退到Array方法上的Ruby select。该方法返回所有购买p而没有sale,这是通过否定销售购买来完成的。

希望这可以清楚范围正在做些什么。

更新2:

可链接的范围!

scope :unsold, lambda { where('id not in (?)', Sale.pluck(:linked_indent_id)) }

在此范围内,选择了id Sale以内的linked_indent_id次购买。

答案 1 :(得分:0)

Rails-ey以数据库为中心的方法:

scope :sold, -> { joins(:sale) }
scope :unsold, -> { includes(:sale).where(sales: {linked_indent_id: nil}) }

(请注意,您必须使用where子句中的表名,而不是关系名称。这是&#39;销售&#39;,不是&#39;销售&#39;。)< / p>