2012-08-30 32 views
1

我有這個代碼與shipment has one invoice一起使用,但現在我不得不將它更改爲shipment has many invoices。我如何修改以下代碼以反映新的關聯?Rails 3.如何通過has_many關係使用reduce?

@totals = { 
    :overall => @shipments.reduce(0) { |total, shipment| total + shipment.invoice.customer_total }, 
    :paid => @shipments.reduce(0) { |total, shipment| total + shipment.invoice.customer_amount_paid }, 
    :balance => @shipments.reduce(0) { |total, shipment| total + shipment.invoice.customer_open_balance } 
    } 

回答

2

我會做這樣的事情:

# collect all the invoices at once 
invoices = @shipments.map(&:invoices).flatten 

@totals = { 
    # collect all the customer_totals and sum them... repeat 
    :overall => invoices.map(&:customer_total).reduce(0, :+), 
    :paid => invoices.map(&:customer_amount_paid).reduce(0, :+), 
    :balance => invoices.map(&:customer_open_balance).reduce(0, :+) 
} 

注:Enumerable#reduce,與許多其他方法沿着Enumerable,有一個塊或符號的工作名稱的方法或者操作者的能力。這使您可以用[1,2,3,4,5].reduce(:+)替換[1,2,3,4,5].reduce{ |sum, x| sum + x }

另外,如果未給出參數,則將集合中的第一個值假定爲備忘錄的初始值。

正如tokland指出的那樣,如果數組爲空,您需要將備忘錄的初始值作爲0傳遞。這可以防止您獲得@totals[:balance] == nil

+2

'reduce(0,:+)'是處理空數組所必需的。和'map' +'flatten(1)'='flat_map'。我確信這可以用SQL來完成,但這是一個很好的Ruby方法。 – tokland

+0

@tokland非常好的一點。謝謝! – Kyle

相關問題