Read more

The numericality validator does not care about your BigDecimal precision

Michael Leimstädtner
June 15, 2023Software engineer at makandra GmbH

Looking at the source code of the validates_numericality_of validator Show archive.org snapshot , it becomes clear that it converts the attribute in question to either an integer or float:

if configuration[:only_integer]
  unless raw_value.to_s =~ /\A[+-]?\d+\Z/
    record.errors.add(attr_name, configuration[:message] || ActiveRecord::Errors.default_error_messages[:not_a_number])
    next
  end
  raw_value = raw_value.to_i
else
 begin
    raw_value = Kernel.Float(raw_value.to_s)
  rescue ArgumentError, TypeError
    record.errors.add(attr_name, configuration[:message] || ActiveRecord::Errors.default_error_messages[:not_a_number])
    next
  end
end
Illustration online protection

Rails professionals since 2007

Our laser focus on a single technology has made us a leader in this space. Need help?

  • We build a solid first version of your product
  • We train your development team
  • We rescue your project in trouble
Read more Show archive.org snapshot

This might bite you for BigDecimals with a high precision as the casted float value might be rounded up or down. In these cases you'll have to write your own numericality validator.

One example would be a validation that your attribute is less_than: 100000. The Float 99999.999999999999 will NOT pass this check because it's rounded up. It will however most likely never affect any of your users as this is only broken in the most extreme case shown above.

Posted by Michael Leimstädtner to makandra dev (2023-06-15 10:40)