Fix dirty check for Float::NaN and BigDecimal::NaN

Float::NaN and BigDecimal::NaN in Ruby are [special values](https://bugs.ruby-lang.org/issues/1720) and can't be compared with `==`.
This commit is contained in:
Marcelo Lauxen 2021-07-21 08:45:09 -03:00
parent 5d78c54a46
commit d1df4c100f
No known key found for this signature in database
GPG Key ID: 7B98E50D1D67556D
4 changed files with 20 additions and 1 deletions

View File

@ -1,3 +1,10 @@
* Fix dirty check for Float::NaN and BigDecimal::NaN.
Float::NaN and BigDecimal::NaN in Ruby are [special values](https://bugs.ruby-lang.org/issues/1720)
and can't be compared with `==`.
*Marcelo Lauxen*
* Fix `to_json` for `ActiveModel::Dirty` object.
Exclude `mutations_from_database` attribute from json as it lead to recursion.

View File

@ -25,10 +25,18 @@ module ActiveModel
end
def changed?(old_value, _new_value, new_value_before_type_cast) # :nodoc:
super || number_to_non_number?(old_value, new_value_before_type_cast)
(super || number_to_non_number?(old_value, new_value_before_type_cast)) &&
!equal_nan?(old_value, new_value_before_type_cast)
end
private
def equal_nan?(old_value, new_value)
(old_value.is_a?(::Float) || old_value.is_a?(BigDecimal)) &&
old_value.nan? &&
old_value.instance_of?(new_value.class) &&
new_value.nan?
end
def number_to_non_number?(old_value, new_value_before_type_cast)
old_value != nil && non_numeric_string?(new_value_before_type_cast.to_s)
end

View File

@ -66,6 +66,8 @@ module ActiveModel
assert_not type.changed?(5.0, 5.0, "5.0")
assert_not type.changed?(-5.0, -5.0, "-5.0")
assert_not type.changed?(5.0, 5.0, "0.5e+1")
assert_not type.changed?(BigDecimal("0.0") / 0, BigDecimal("0.0") / 0, BigDecimal("0.0") / 0)
assert type.changed?(BigDecimal("0.0") / 0, 0.0 / 0.0, 0.0 / 0.0)
end
def test_scale_is_applied_before_precision_to_prevent_rounding_errors

View File

@ -28,6 +28,8 @@ module ActiveModel
assert_not type.changed?(5.0, 5.0, "5.0")
assert_not type.changed?(500.0, 500.0, "0.5E+4")
assert_not type.changed?(nil, nil, nil)
assert_not type.changed?(0.0 / 0.0, 0.0 / 0.0, 0.0 / 0.0)
assert type.changed?(0.0 / 0.0, BigDecimal("0.0") / 0, BigDecimal("0.0") / 0)
end
end
end