Andy Harvey
Andy Harvey

Reputation: 12663

How to add BigDecimal values in a Rails app

In a Rails 3.2 app I have defined two methods that perform a calculation and return a big decimal value.

Def Func1
  Model1.price * Model1.qty
End 

Def Func2
   Model2.price * Model2.qty
End

I don't know if this relevant, but the :qty field is a counter cache column recording the number of associated has_many records.

I now want to calculate the sum of Func1 and Func2. If I try

Def FuncTotal
   Func1 + Func2
End 

it returns the two values concatenated, not the sum. i.e. if Func1=15.45 and Func2=24.76, then FuncTotal=15.4524.76.

I also tried

Def FuncTotal
   Func1.to_s + Func2.to_s
End

But this also concatenates.

I assume this issue is occurring because the calculation is based on BigDecimal values. In which case it seems strange to me that the price*qty calculation returns the correct product.

How can I add two BigDecimal values together?

Many thanks

EDIT

This is an example console output

> 1=Model1.find(1)
=> #<Model1 id:1......
> 2.Model2.find(2)
=> #<Model2 id:2....
> 1total=1.func1
=> [#<BigDecimal:10a5cd888,'0.25E4',9(36)>] 
> 2.total=2func2
=> [#<BigDecimal:10a5c7348,'0.5E3',9(36)>]
> 1+2
=> [#<BigDecimal:10a5cd888,'0.25E4',9(36)>, #<BigDecimal:10a5c7348,'0.5E3',9(36)>]

Strange!

EDIT

My columns are defined as follows.

Price is the same in both models

t.decimal  "price",  :precision => 12, :scale => 2

Quantity is more or less the same in both models

t.integer  "model1_children_count", :default => 0

and in the child model

belongs_to :model1, :counter_cache => true

EDIT

The full Func1 and Func2 is as follows, located within a parent model that has_many Model1s and Model2s.

Class Parent
  def total_cost_of_model1
    model1s.collect { |model1s| model1.price * model1.quantity }
  end
end

Upvotes: 1

Views: 2098

Answers (2)

corroded
corroded

Reputation: 21604

Your total cost function is calling collect which returns an array, which when concatenated will return a concatenated array. You have to return the correct type(BigDecimal) if you want to add it up using "+"

Upvotes: 2

Waynn Lue
Waynn Lue

Reputation: 11385

Are you sure they're BigDecimals? I'm actually getting the correct behavior here.

irb(main)> a = BigDecimal.new("1")
=> #<BigDecimal:102773230,'0.1E1',9(18)>
irb(main)> b = BigDecimal.new("2")
=> #<BigDecimal:100dd1a48,'0.2E1',9(18)>
irb(main)> c = a + b
=> #<BigDecimal:1026502e0,'0.3E1',9(27)>
irb(main)> c.to_i
=> 3

Upvotes: 0

Related Questions