Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix non_numeric_string? #33804

Merged
merged 1 commit into from
Sep 7, 2018
Merged

Fix non_numeric_string? #33804

merged 1 commit into from
Sep 7, 2018

Conversation

yskkin
Copy link
Contributor

@yskkin yskkin commented Sep 6, 2018

For example, dirty checking was not right for the following case:

model.int_column = "+5"
model.float_column = "0.5E+1"
model.decimal_column = "0.5e-3"

Fixes #33801

@rails-bot
Copy link

Thanks for the pull request, and welcome! The Rails team is excited to review your changes, and you should hear from @sgrif (or someone else) soon.

If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes.

This repository is being automatically checked for code quality issues using Code Climate. You can see results for this analysis in the PR status below. Newly introduced issues should be fixed before a Pull Request is considered ready to review.

Please see the contribution instructions for more information.

@@ -29,7 +29,7 @@ def non_numeric_string?(value)
# 'wibble'.to_i will give zero, we want to make sure
# that we aren't marking int zero to string zero as
# changed.
value.to_s !~ /\A-?\d+\.?\d*\z/
value.to_s !~ /\A[-+]?\d+\.?\d*([eE][-+]\d+)?\z/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use match? to avoid creating unused match object and unused captures?

diff --git a/activemodel/lib/active_model/type/helpers/numeric.rb b/activemodel/lib/active_model/type/helpers/numeric.rb
index 16e14f9e5f..c9519dc908 100644
--- a/activemodel/lib/active_model/type/helpers/numeric.rb
+++ b/activemodel/lib/active_model/type/helpers/numeric.rb
@@ -29,7 +29,7 @@ def non_numeric_string?(value)
             # 'wibble'.to_i will give zero, we want to make sure
             # that we aren't marking int zero to string zero as
             # changed.
-            value.to_s !~ /\A-?\d+\.?\d*\z/
+            !/\A[-+]?\d+\.?\d*(?:[eE][-+]\d+)?\z/.match?(value.to_s)
           end
       end
     end

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @kamipo.
I found 5e2 is also valid expression, so I'll change regex to /\A[-+]?\d+\.?\d*(?:[eE][-+]?\d+)?\z/

I also found "E-notataion" is valid for to_d and to_f but not to_i:

irb(main):001:0> require 'bigdecimal'
=> true
irb(main):002:0> require 'bigdecimal/util'
=> true
irb(main):003:0> '5e+2'.to_d
=> 0.5e3
irb(main):004:0> '5e+2'.to_f
=> 500.0
irb(main):005:0> '5e+2'.to_i
=> 5

Should I overwrite this method for AM::Type::Integer?

@@ -60,6 +60,7 @@ def test_changed?
assert type.changed?(5.0, 5.0, "5.0wibble")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now I come to think this test is not appropriate.
model.int_column = "5.0wibble" and "5.0wibble".to_i both result in 5.

We may not need \z in regex.

@yskkin
Copy link
Contributor Author

yskkin commented Sep 6, 2018

To avoid invalid numeric expression like 'wibble' to be type-casted to 0 as commet says,
It is enough to see leading character is digit.

I updated PR based on this.

@yskkin
Copy link
Contributor Author

yskkin commented Sep 7, 2018

@rafaelfranca @kamipo Thank you for review!
PR updated.

@@ -21,9 +21,11 @@ def test_type_cast_float_from_invalid_string
def test_changing_float
type = Type::Float.new

assert type.changed?(5.0, 5.0, "5wibble")
assert type.changed?(5.0, 0, "wibble")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add assert type.changed?(0, 0, "wibble") too?
Since type.changed? always returns true if differ old_value and new_value regardless of the result of non_numeric_string?.

For example, dirty checking was not right for the following case:

```
model.int_column = "+5"
model.float_column = "0.5E+1"
model.decimal_column = "0.5e-3"
```

It is enough to see whether leading character is a digit for avoiding
invalid numeric expression like 'wibble' to be type-casted to 0, as
this method's comment says.

Fixes rails#33801
@yskkin
Copy link
Contributor Author

yskkin commented Sep 7, 2018

@kamipo done. Do you have any other concerns?

@kamipo kamipo merged commit c3e5695 into rails:master Sep 7, 2018
@kamipo
Copy link
Member

kamipo commented Sep 7, 2018

Thanks!

@yskkin yskkin deleted the num_string branch September 8, 2018 01:15
@yskkin
Copy link
Contributor Author

yskkin commented Sep 11, 2018

I think this should be backported.

kamipo added a commit that referenced this pull request Sep 11, 2018
@kamipo
Copy link
Member

kamipo commented Sep 11, 2018

Backported in b433433.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants