2016-12-09 14 views
0

Rubyのように以下のコードをリファクタリングしたいと思います。Rails;総計

def cal_total 
    total = nil 
    items.each do |item| 
     total = total + item.itemable.amount 
    end 
    total 
end 

基本的にオブジェクトを反復し、各量をフェッチして合計を返します。

更新

total = item.itemable.amountは正しいです。

+0

アイテム化可能なものは、単一のクエリでも実行できます – RSB

+0

アイテムは他のモデルと多相関係を持っています。 – Tosh

+0

@TSHあなたの関連付けを追加してください。 'items.itemable' - これは機能しますか? – dp7

答えて

1

あなたは次のことを試すことができます。

items.map(&:amount).inject(0, &:+) 

正確な構文は、あなたのコードに依存します。必ずしもRuby Wayではありませんが、より簡潔で機能的なスタイルです。

+3

'items.map(&:amount).reduce(&:+)'またはRails 'items.map(&:amount).sum'としても書けます。 – user000001

+0

' items.itemable.map (&:amount).inject(0、&:+) ' – Kris

+0

@ user000001これは本当ですが、' inject'と 'reduce'はルビーでほとんど同じです。 – Sid

0

ことはあなたの関連性のためにこれを試してみてください:

items.map(&:itemable).sum(&:amount) 

OR

items.map { |i| i.itemable.amount }.sum 
+0

これは動作しません。 'NoMethodError:undefined method + '' – Tosh

+0

@TSH更新された回答 – dp7

+0

あなたの回答編集は私の答えを複製しました! :) – RSB

1

あなたがこれを行うことができ、私は

items = Item.includes(:itemable) 
total = items.map{ |item| item.itemable.amount }.sum 

n + 1クエリの問題を回避するために希望をincludesを使用して積極的なロードしていますそれは助ける!

0

あなたはリファクタリング中に行うことができますもう一つはありsum

items.map{ |item| item.itemable.amount }.sum 
1

を利用することができます。アイテムのモデルでは

、あなたは今、あなたは.オペレータなしで量を得ることができ

class Item 
    delegate :amount, to: :itemable, prefix: true, allow_nil: true 
end 

をitemableする金額メソッドを委任することができます。あなたが書くことができますprefix: false

items.map{ |item| item.itemable_amount }.sum 

items.map{ |item| item.amount }.sum 
0

あなたは合計をこのように取得し、私はこれがベストプラクティスとパフォーマンスの問題の中で最も効率的であると考えることができます

items.map(:&itemable).pluck(:amount).reduce(:+)