diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb index d9348ece1e..f6c15a70aa 100644 --- a/activemodel/lib/active_model/validations/numericality.rb +++ b/activemodel/lib/active_model/validations/numericality.rb @@ -71,6 +71,8 @@ module ActiveModel raw_value if raw_value.is_a?(Range) elsif raw_value.is_a?(Float) parse_float(raw_value, precision, scale) + elsif raw_value.is_a?(BigDecimal) + round(raw_value, scale) elsif raw_value.is_a?(Numeric) raw_value elsif is_integer?(raw_value) @@ -81,7 +83,11 @@ module ActiveModel end def parse_float(raw_value, precision, scale) - (scale ? raw_value.truncate(scale) : raw_value).to_d(precision) + round(raw_value, scale).to_d(precision) + end + + def round(raw_value, scale) + scale ? raw_value.round(scale) : raw_value end def is_number?(raw_value, precision, scale) diff --git a/activerecord/test/cases/validations/numericality_validation_test.rb b/activerecord/test/cases/validations/numericality_validation_test.rb index 91cd6a0b0d..d79f4a0e1a 100644 --- a/activerecord/test/cases/validations/numericality_validation_test.rb +++ b/activerecord/test/cases/validations/numericality_validation_test.rb @@ -103,6 +103,21 @@ class NumericalityValidationTest < ActiveRecord::TestCase assert_not_predicate subject, :valid? end + def test_virtual_attribute_with_precision_and_scale + model_class.attribute(:virtual_decimal_number, :decimal, precision: 4, scale: 2) + model_class.validates_numericality_of( + :virtual_decimal_number, less_than_or_equal_to: 99.99 + ) + + subject = model_class.new(virtual_decimal_number: 99.994) + assert_equal 99.99.to_d(4), subject.virtual_decimal_number + assert_predicate subject, :valid? + + subject = model_class.new(virtual_decimal_number: 99.999) + assert_equal 100.00.to_d(4), subject.virtual_decimal_number + assert_not_predicate subject, :valid? + end + def test_aliased_attribute model_class.validates_numericality_of(:new_bank_balance, greater_or_equal_than: 0) diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb index 4f98a6b7fc..f108d4ca65 100644 --- a/activerecord/test/cases/validations_test.rb +++ b/activerecord/test/cases/validations_test.rb @@ -187,9 +187,17 @@ class ValidationsTest < ActiveRecord::TestCase validates_numericality_of :wibble, greater_than_or_equal_to: BigDecimal("97.18") end - assert_not_predicate klass.new(wibble: "97.179"), :valid? - assert_not_predicate klass.new(wibble: 97.179), :valid? - assert_not_predicate klass.new(wibble: BigDecimal("97.179")), :valid? + ["97.179", 97.179, BigDecimal("97.179")].each do |raw_value| + subject = klass.new(wibble: raw_value) + assert_equal 97.18.to_d(4), subject.wibble + assert_predicate subject, :valid? + end + + ["97.174", 97.174, BigDecimal("97.174")].each do |raw_value| + subject = klass.new(wibble: raw_value) + assert_equal 97.17.to_d(4), subject.wibble + assert_not_predicate subject, :valid? + end end def test_numericality_validator_wont_be_affected_by_custom_getter