是否有一种简单的方法可以在Rails中计算求和积?

问题描述 投票:0回答:1

我有一个PositionGroup,即has_many :positions

每当触摸position_group对象时,我都想像这样更新pg.average_price

# Average Price = ((position1.transaction_price * (position1.volume/total_volume) + 
# position2.transaction_price * (position2.volume/total_volme)) 

在我的回调方法中,我尝试了这个:

  def update_average_price
    total_volume = positions.sum(:volume)
    avg_price = positions.sum("transaction_price * (volume/#{total_volume})")
    update_column(:average_price, avg_price)
  end

但是当存在多个avg_price时检查positions的值时,我得到的是0.0

这是我针对此特定功能的规范:

it "should calculate the Weighted Average Purchase Price of all positions" do
  # Position 3: Price = 20, volume = 200
  # (Position 1 Price * (Position 1 Units/Total # of Units)) +
  # (Position 2 Price * (Position 2 Units/Total # of Units)) +
  # (Position 3 Price * (Position 3 Units/Total # of Units))
  # ($10 * (100/400)) + ($15 * (100/400) + $20 * (100/400)) =
  # ($2.50 + $3.75 + $5) = $11.25
  price3 = 20
  pos3 = create(:position, stock: stock, portfolio: portfolio, transaction_price: 20, current_price: price3, action: :buy, volume: 200, position_group: pg)
  expect(pg.average_price).to eql 11.25
end

这是我运行它时的结果:

1) PositionGroup methods should calculate the Weighted Average Purchase Price of all positions
     Failure/Error: expect(pg.average_price).to eql 11.25

       expected: 11.25
            got: 0.0

       (compared using eql?)

我很确定问题是此行,来自我在update_average_price上的回调方法PositionGroup

avg_price = positions.sum("transaction_price * (volume/#{total_volume})")

是否有更好的方法来解决此问题,或者在我不应该的时候还有其他东西让我得到0.0

ruby-on-rails ruby-on-rails-5
1个回答
0
投票
avg_price = positions.sum("transaction_price * (volume/#{total_volume.to_f})")

[to_f丢失,转换为float以获取小数。

示例

irb(main):022:0> Position.all
  Position Load (0.3ms)  SELECT "positions".* FROM "positions" LIMIT ?  [["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<Position id: 1, transaction_price: 0.5e2, volume: 150, position_group_id: 1>, #<Position id: 2, transaction_price: 0.1e1, volume: 50, position_group_id: 1>]>
irb(main):023:0> Position.all.sum("transaction_price * (volume/#{total_volume.to_f})")
   (0.2ms)  SELECT SUM(transaction_price * (volume/200.0)) FROM "positions"
=> 37.75
© www.soinside.com 2019 - 2024. All rights reserved.