【问题标题】:Scope for an optional has_one association with itself与自身的可选 has_one 关联的范围
【发布时间】:2014-01-10 02:31:48
【问题描述】:

我有一个模型缩进。我正在使用 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

我只需要一个 Purchase 类的范围,使用它我可以找到所有没有与之关联的销售的购买。

我使用 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

在耦合查询的这两个部分时我缺少什么?

【问题讨论】:

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


    【解决方案1】:

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

    所以我的理解是任何未售出的东西都是购买减去销售。以下应该为您提供该列表:

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

    更新:

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

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

    希望这能澄清一下示波器的作用。

    更新 2:

    一个可链接的作用域!

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

    在此范围内,ids 的购买不在Salelinked_indent_id 中被选中。

    【讨论】:

    • 哇。一次性完成。
    • 非常感谢。你也可以稍微解释一下你在那里做了什么,以便我和其他人可以更好地理解。
    • 再次感谢。我考虑过在 Rails 中过滤购买,但无法以这种 DRY 的方式完成。此外,我将在自动完成选择菜单时使用此范围进行搜索。有点担心它是否会影响性能。
    • @Bot,请看我的更新。你说得对,Array#select 不会使其可链接,这是 Rails 范围的最佳功能之一。
    • 非常感谢。这是我从您的答案中提取的这种情况下需要的内容。 scope :unsold, where('id not in (?)', Sale.pluck(:linked_indent_id))
    【解决方案2】:

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

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

    (请注意,您必须在where 子句中使用表名,而不是关系名。即“sales”,而不是“sale”。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-12
      相关资源
      最近更新 更多