0

I am using this function in my User model to populate a select box in a form:

def outstanding_invoices
  invoices.to_a.select { |invoice| invoice.balance < 0 }
end

The problem is that balance is not a database field but a method that calculates something.

So it takes an awful lot of SQL queries to generate the select box because the function above iterates over every single invoice that the user has.

Is there a faster way to generate the select box, ideally using one SQL query only?

A simple alternative would probably be storing the balance of each invoice in the database, but I am somehow reluctant to do that because I want to keep my database to a minimum.

Thanks for any help.

4

1 回答 1

2

根据使用计算出的货币价值的经验,在很多情况下,将计算出的价值与用于计算该价值的参数一起存储是有意义的——这样您就可以对计算出的价值运行查询,但您也可以追溯至该值是如何计算的。

在您的发票示例中,我建议您在模型中实现after_save回调。Payment例如:

class Payment < ActiveRecord::Base
  belongs_to :invoice

  def after_save
    invoice.update_balance
  end
end

class Invoice
  has_many :payments

  def self.with_open_balance
    where("current_balance > 0")
  end

  def update_balance
    update_attributes(:current_balance => balance)
  end

  def balance
    invoiced_amount - payments.sum(:amount)
  end
end

使用这种方法,您现在可以调用customer.invoices.with_open_balance以获取该客户的所有未结发票。每当保存付款时,付款所属的发票将重新计算其余额并将计算的值存储在同一数据库事务中,以确保一致性。

于 2012-10-20T18:02:54.140 回答