2012-10-20 20 views
0

我使用這個功能在我User模型來填充一個選擇框的形式:通過虛擬屬性而非數據庫字段過濾記錄?

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

的問題是,balance不是一個數據庫字段,但計算的東西的方法。

因此,需要大量的SQL查詢來生成選擇框,因爲上面的函數遍歷了所具有的每個單獨的invoice

是否有更快的方式來生成選擇框,理想情況下只使用一個SQL查詢?

一個簡單的選擇很可能會在數據庫中存儲的每個invoicebalance,但我不知怎麼不願意這樣做,因爲我想保持我的數據庫來最低。

感謝您的任何幫助。

回答

2

基於計算貨幣值的經驗,在很多情況下,將計算值與用於計算該值的參數一起存儲是有意義的 - 這樣您就可以針對計算值運行查詢,但是您也可以對於如何計算價值具有可追溯性。

在您的發票示例中,我建議您在Payment模型中實施after_save回調。例如:

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讓所有客戶開放的發票。每當保存付款時,付款所屬的發票將重新計算其餘額並將該計算值存儲在同一數據庫交易中,以確保一致性。

+0

好的,謝謝你的幫助。試圖實現這一點。儘管'update_attributes'方法在這裏引起了'stack overlflow'。除此之外還有其他選擇嗎? – Tintin81

+0

剛剛發現'update_column(:current_balance,balance)'是要走的路。只有通過Rails> = v3.1 ... – Tintin81

+0

'update_attributes'應該可以正常工作 - 確保你沒有任何地方的遞歸方法調用(例如命名衝突)。你也可以嘗試'update_attribute',但這有其他的含義,所以請查看文檔。 –