我在User
模型中使用此功能来填充表单中的选择框:
def outstanding_invoices
invoices.to_a.select { |invoice| invoice.balance < 0 }
end
问题是balance
不是数据库字段,而是计算某些东西的方法。
因此,生成选择框需要大量的SQL查询,因为上面的函数会迭代invoice
所拥有的每一个user
。
是否有更快的方法来生成选择框,理想情况下只使用一个SQL查询?
一个简单的替代方法可能是将每个balance
的{{1}}存储在数据库中,但我不知道这样做是因为我想将数据库保持在最低限度。
感谢您的帮助。
答案 0 :(得分: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
以获取该客户的所有未结发票。每当保存付款时,付款所属的发票将重新计算其余额并将该计算值存储在同一数据库事务中,以确保一致性。