aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Griffin <sean@thoughtbot.com>2014-06-24 06:55:24 -0600
committerSean Griffin <sean@thoughtbot.com>2014-06-24 08:32:30 -0600
commit50fa366783c2403d909a6fa5b7fc6d4c7fdacf7f (patch)
tree20c9ec3ac39490d6a56c44013bfe92a985c193d0
parent9ac1ce11ad9ec22157d2e542437c5c5cccaf58fe (diff)
downloadrails-50fa366783c2403d909a6fa5b7fc6d4c7fdacf7f.tar.gz
rails-50fa366783c2403d909a6fa5b7fc6d4c7fdacf7f.tar.bz2
rails-50fa366783c2403d909a6fa5b7fc6d4c7fdacf7f.zip
Always assume strings with non-numeric characters change numeric types
We previously only did this if the old value was zero, to make sure numericality validations run and failed if the user gave 'wibble' as the value, which would be type cast to 0. However, numericality validations will fail if there are any non-numeric characters in the string, so 5 -> '5wibble' should also be marked as changed.
-rw-r--r--activerecord/CHANGELOG.md14
-rw-r--r--activerecord/lib/active_record/type/numeric.rb6
-rw-r--r--activerecord/test/cases/types_test.rb18
3 files changed, 35 insertions, 3 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 33dec99ec7..6fc770d293 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,17 @@
+* Assume numeric types have changed if they were assigned to a value that
+ would fail numericality validation, regardless of the old value. Previously
+ this would only occur if the old value was 0.
+
+ Example:
+
+ model = Model.create!(number: 5)
+ model.number = '5wibble'
+ model.number_changed? # => true
+
+ Fixes #14731.
+
+ *Sean Griffin*
+
* `reload` no longer merges with the existing attributes.
The attribute hash is fully replaced. The record is put into the same state
as it would be with `Model.find(model.id)`.
diff --git a/activerecord/lib/active_record/type/numeric.rb b/activerecord/lib/active_record/type/numeric.rb
index a7bf0657b9..fa43266504 100644
--- a/activerecord/lib/active_record/type/numeric.rb
+++ b/activerecord/lib/active_record/type/numeric.rb
@@ -16,13 +16,13 @@ module ActiveRecord
end
def changed?(old_value, _new_value, new_value_before_type_cast) # :nodoc:
- super || zero_to_non_number?(old_value, new_value_before_type_cast)
+ super || number_to_non_number?(old_value, new_value_before_type_cast)
end
private
- def zero_to_non_number?(old_value, new_value_before_type_cast)
- old_value == 0 && non_numeric_string?(new_value_before_type_cast)
+ def number_to_non_number?(old_value, new_value_before_type_cast)
+ old_value != nil && non_numeric_string?(new_value_before_type_cast)
end
def non_numeric_string?(value)
diff --git a/activerecord/test/cases/types_test.rb b/activerecord/test/cases/types_test.rb
index 731f8cfba3..961aae88cb 100644
--- a/activerecord/test/cases/types_test.rb
+++ b/activerecord/test/cases/types_test.rb
@@ -79,11 +79,29 @@ module ActiveRecord
assert_nil type.type_cast_from_user(1.0/0.0)
end
+ def test_changing_integers
+ type = Type::Integer.new
+
+ assert type.changed?(5, 5, '5wibble')
+ assert_not type.changed?(5, 5, '5')
+ assert_not type.changed?(5, 5, '5.0')
+ assert_not type.changed?(nil, nil, nil)
+ end
+
def test_type_cast_float
type = Type::Float.new
assert_equal 1.0, type.type_cast_from_user("1")
end
+ def test_changing_float
+ type = Type::Float.new
+
+ assert type.changed?(5.0, 5.0, '5wibble')
+ assert_not type.changed?(5.0, 5.0, '5')
+ assert_not type.changed?(5.0, 5.0, '5.0')
+ assert_not type.changed?(nil, nil, nil)
+ end
+
def test_type_cast_decimal
type = Type::Decimal.new
assert_equal BigDecimal.new("0"), type.type_cast_from_user(BigDecimal.new("0"))