Dan S.
Dan S.

Reputation: 162

Ruby on Rails decimal comparison stopped working

I have been using a state object in the database that keeps track of what seed data has been loaded into it. The structure of the table is:

create_table "toolkit_states", force: :cascade do |t|
  t.boolean "signups", default: true
  t.decimal "database_version", precision: 5, scale: 2
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

The seeds.rb file checks the database_version and runs blocks of code and then sets the database_version after running the block. It has worked fine from versions 0.1 up to 0.55.

I added a new block of seed data. To run that block the database_version is checked and it should be 0.56. The following comparison does not work:

if state.database_version == 0.56

For some reason, the number 0.56 cannot be evaluated for equality with the value stored in the database. It has worked on all the values up to 0.56.

Here is a rails console session:

irb(main):001:0> state = ToolkitState.first
ToolkitState Load (0.4ms)  SELECT  "toolkit_states".* FROM "toolkit_states" ORDER BY "toolkit_states"."id" ASC LIMIT $1  [["LIMIT", 1]]
=> #<ToolkitState id: 1, signups: false, database_version: 0.56e0, created_at: "2018-12-27 17:04:50", updated_at: "2018-12-27 17:04:56">
irb(main):002:0> state.database_version == 0.56
=> false
irb(main):003:0> state.database_version == 0.56e0
=> false
irb(main):004:0> state.database_version == 0.56.to_f
=> false
irb(main):005:0> state.database_version.to_f == 0.56
=> true

When I convert the value with a "to_f", the comparison works. My problem is that it as worked well without this conversion up to the value, 0.56

Upvotes: 0

Views: 404

Answers (2)

Jan Matuszewski
Jan Matuszewski

Reputation: 148

It occurs because state.database_version is an instance of BigDecimal class. This article explain why it is BigDecimal.

Look at this example:

BigDecimal('0.56e0')
=> 0.56e0
irb(main):008:0> BigDecimal('0.56e0') == 0.56
=> false
irb(main):009:0> BigDecimal('0.56e0').to_f
=> 0.56

As you can see 0.56e0 after transformation to float type becomes 0.56 and your comparison returns true.

Nate explained more briefly why it's happening in this comment.

Upvotes: 1

Dan S.
Dan S.

Reputation: 162

irb(main):001:0>  c = BigDecimal('0.56e0')
=> 0.56e0
irb(main):002:0> c == 0.56
=> false
irb(main):003:0>  c = BigDecimal('0.55e0')
=> 0.55e0
irb(main):004:0> c == 0.55
=> true

Works for 0.55 and not for 0.56 Rails bug?

Upvotes: 0

Related Questions