Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is postgreSQL storing a decimal field as a BigDecimal hash?

I have the following model/table in rails3/postgreSQL:

create_table "admin_reports", :force => true do |t|
  t.string   "report"
  t.decimal  "result"
  t.string   "result_type"
  t.datetime "created_at"
  t.datetime "updated_at"
end

On production, AdminReports.result is not storing the decimal but rather a hash:

AdminReport.last

=> #<AdminReport id: 4, report: "dau", result: #<BigDecimal:cbca0f0,'0.8E1',4(8)>, result_type: "percentage", created_at: "2012-02-28 22:05:15", updated_at: "2012-02-28 22:05:15">

Where I would expect to see:

AdminReport.last

=> #<AdminReport id: 4, report: "dau", result: 10.10, result_type: "percentage", created_at: "2012-02-28 22:05:15", updated_at: "2012-02-28 22:05:15">

In the rails console, even if I try to set the result field manually like so:

@a = AdminReport.last
@a.result = 8.89
@a.save

It still shows AdminReport.result as a BigDecimal hash. Any ideas what's going on here?

Thanks

like image 795
AnApprentice Avatar asked Feb 28 '12 22:02

AnApprentice


1 Answers

You're using a decimal column:

create_table "admin_reports", :force => true do |t|
  #...
  t.decimal  "result"
  #...
end

That usually means that you want to use a fixed number of decimal places so you probably want to specify the :precision and :scale options as well. When ActiveRecord sees a decimal column, it converts the value to Ruby's BigDecimal so that you can maintain the desired number of decimal places while in Ruby-land; if AR used a floating point value then you'd run into all the usual floating point problems and you could end up pulling one value out of the database and putting a different one back without intentionally changing it, using BigDecimal avoids the problem entirely.

When you see this:

#<BigDecimal:cbca0f0,'0.8E1',4(8)>

You're just seeing the standard inspect output from BigDecimal. If you use to_s (or "#{...}"), you'll see something more familiar.

So there's nothing to worry about. If you need to use non-integer arithmetic but don't want all the problems of floating point then a decimal column (with :precision and :scale) is the right choice.

like image 54
mu is too short Avatar answered Oct 29 '22 10:10

mu is too short