【问题标题】:Ruby on Rails 3: How to find associated records through associated method?Ruby on Rails 3:如何通过关联方法找到关联记录?
【发布时间】:2012-09-27 12:39:32
【问题描述】:

我有许多项目和付款的发票。

这是我的发票模型(至少是其中的一部分):

def total
  items.sum { |item| item.total }
end

def balance
  self.payments.sum(:amount) - self.total
end

现在在付款视图中,我正在尝试查找余额小于 0 的所有发票:

<%= f.select(:invoice_id, current_user.invoices.where("balance > ?", 0)) %>

这当然行不通,因为 balance 不是一列。但是我怎样才能在那里插入一个方法呢?

感谢您的帮助。

【问题讨论】:

    标签: ruby-on-rails


    【解决方案1】:

    您有几个选择。您始终可以将balance 设为一列(在添加付款或项目时酌情更新),这样您就可以有效地进行此类查询。

    但是,您可以只使用简单的 Ruby 方法 - 具体来说,Array#select。类似的东西

    current_user.invoices.to_a.select {|invoice| invoice.balance < 0}
    

    会带你到那里。但是,如果用户有大量发票,效率将不会很高。

    更新:另外,如果您这样做,您将点击N+1 query situation,因为每张发票都需要从数据库中检索其项目和付款。为避免这种情况,您需要在原始查询中包含项目和付款,如下所示:

    current_user.invoices.includes(:items, :payments).to_a.select{ ... }
    

    【讨论】:

    • 谢谢,安迪!会尝试你的建议。但这真的那么低效吗?如果我将余额存储在数据库中,那会不会是“冗余数据”,因为它可以使用另外两个表列来计算?我是 Ruby 和 Rails 的新手,所以我想知道专业人士是如何做到的。现在,我正在尝试尽可能使用虚拟属性。不知道这是否好...
    • 效率会很低。首先,当您只对少数几个感兴趣时,您返回所有发票 - 这会减慢您的查询速度并浪费一些内存。其次,要每次重新计算余额,您必须遍历所有发票的所有付款和所有项目,这将花费几个 cpu 周期。所以它会影响性能 - 它有多糟糕取决于每个用户的发票数量,以及你计算的频率。
    • 此外,最佳实践是避免将逻辑放入视图中。您可以在控制器中进行查询,并使用实例变量将结果传递给视图,然后您可以执行&lt;%= f.select(:invoice_id, @outstanding_invoices) %&gt;。更好的是,您可以将 outstanding_invoices 设为用户模型上的方法。
    • 好的,所以如果我有一个所有用户发票的索引视图,显示每张发票的(计算的)余额和总额,最好将这两个虚拟属性转换为表格列...?跨度>
    • 是的,在这种情况下,我会这样做。虚拟属性很棒,但只有在计算它们不太昂贵时 - 例如将full_namefirst_namelast_name 放在一起。
    猜你喜欢
    • 1970-01-01
    • 2015-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-05
    • 1970-01-01
    相关资源
    最近更新 更多