BigBinary Blog

We write about Ruby on Rails, React.js, React Native, remote work, open source, engineering and design.

Rails adds accurate numerical validation

Let's see an example of numerical validation of very large numbers.

class Score
  validates :total, numericality: { less_than_or_equal_to: 10_000_000_000_000_000 }

> score = (10_000_000_000_000_000 + 1).to_s)
#=> 1.0e+16

> score.invalid?
#=> false

Here, we have added numerical validation on total column of Score model that it should be less than 10_000_000_000_000_000.

After that we have created one instance of this model with total greater than allowed value. This should result in an invalid object as it violates the numericality criteria.

But it is still valid. We can also see that value of total has been converted into floating number instead of integer. This happens because Rails used to convert the input to float if it was not already numeric.

The real problem is here is that the floating point comparison of the Ruby language itself which is not accurate for very large numbers.

>> a = (10_000_000_000_000_000 + 1).to_s
=> "10000000000000001"
>> b = Kernel.Float a
=> 1.0e+16
>> c = b + 1
=> 1.0e+16
>> c < b
=> false
>> c > b
=> false

This issue has been fixed in Rails here. Now, if the given string input can be treated as integer, then an integer value is returned instead of float. This makes sure that the comparison works correctly.

# Rails 5.2

> score = (10_000_000_000_000_000 + 1).to_s)
#=> 10000000000000001

> score.invalid?
#=> true

This change is present in Rails 5.2 and above. It also backported to Rails 5.1 and Rails 5.0 branches.

Sushant Mittal in Rails
23, 2017

You might also like

Rails 6.1 adds support for PostgreSQL interval data type

Rails 6.1 allows per environment configuration support for Active Storage

Rails 6.1 adds support for belongs_to to has_many inversing

Rails 6.1 adds strict_loading to warn lazy loading associations

Rails 6.1 adds where.associated to check association presence

Subscribe to our newsletter