Search code examples
ruby-on-railsrubybigdecimal

How to enforce the number of significant digits of a BigDecimal


I defined a decimal field with a scale / significant digits of 4 in mysql (ex. 10.0001 ). ActiveRecord returns it as a BigDecimal.

I can set the field in ActiveRecord with a scale of 5 (ex. 10.00001 ), and save it, which effectively truncates the value (it's stored as 10.0000).

Is there a way to prevent this? I already looked at the BigDecimal class if there is a way to force scale. Couldn't find one. I can calculate the scale of a BigDecimal and return a validation error, but I wonder if there is a nicer way to enforce it.


Solution

  • You could add a before_save handler for your class and include logic to round at your preference, for example:

    class MyRecord < ActiveRecord::Base
      SCALE = 4
      before_save :round_decimal_field
      def round_decimal_field
        self.decimal_field.round(SCALE, BigDecimal::ROUND_UP)
      end
    end
    r = MyRecord.new(:decimal_field => 10.00009)
    r.save!
    r.decimal_field # => 10.0001
    

    The scale factor might even be assignable automatically by reading the schema somehow.

    See the ROUND_* constant names in the Ruby BigDecimal class documentation for other rounding modes.