Skip to content

Commit

Permalink
Merge pull request #43914 from orhantoy/add-only-numeric-option-to-nu…
Browse files Browse the repository at this point in the history
…mericality-validator

Add only_numeric option to numericality validator
  • Loading branch information
rafaelfranca committed Dec 20, 2021
2 parents 330ac56 + 318d690 commit 13e5857
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 3 deletions.
9 changes: 8 additions & 1 deletion activemodel/lib/active_model/validations/numericality.rb
Expand Up @@ -11,7 +11,7 @@ class NumericalityValidator < EachValidator # :nodoc:
RANGE_CHECKS = { in: :in? }
NUMBER_CHECKS = { odd: :odd?, even: :even? }

RESERVED_OPTIONS = COMPARE_CHECKS.keys + NUMBER_CHECKS.keys + RANGE_CHECKS.keys + [:only_integer]
RESERVED_OPTIONS = COMPARE_CHECKS.keys + NUMBER_CHECKS.keys + RANGE_CHECKS.keys + [:only_integer, :only_numeric]

INTEGER_REGEX = /\A[+-]?\d+\z/

Expand Down Expand Up @@ -90,6 +90,10 @@ def round(raw_value, scale)
end

def is_number?(raw_value, precision, scale)
if options[:only_numeric] && !raw_value.is_a?(Numeric)
return false
end

!parse_as_number(raw_value, precision, scale).nil?
rescue ArgumentError, TypeError
false
Expand Down Expand Up @@ -162,6 +166,9 @@ module HelperMethods
# * <tt>:message</tt> - A custom error message (default is: "is not a number").
# * <tt>:only_integer</tt> - Specifies whether the value has to be an
# integer (default is +false+).
# * <tt>:only_numeric</tt> - Specifies whether the value has to be an
# instance of Numeric (default is +false+). The default behavior is to
# attempt parsing the value if it is a String.
# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default is
# +false+). Notice that for Integer and Float columns empty strings are
# converted to +nil+.
Expand Down
20 changes: 18 additions & 2 deletions activemodel/test/cases/validations/numericality_validation_test.rb
Expand Up @@ -19,8 +19,10 @@ def teardown
BIGDECIMAL_STRINGS = %w(12345678901234567890.1234567890) # 30 significant digits
FLOAT_STRINGS = %w(0.0 +0.0 -0.0 10.0 10.5 -10.5 -0.0001 -090.1 90.1e1 -90.1e5 -90.1e-5 90e-5)
INTEGER_STRINGS = %w(0 +0 -0 10 +10 -10 0090 -090)
FLOATS = [0.0, 10.0, 10.5, -10.5, -0.0001] + FLOAT_STRINGS
INTEGERS = [0, 10, -10] + INTEGER_STRINGS
NUMERIC_FLOATS = [0.0, 10.0, 10.5, -10.5, -0.0001]
NUMERIC_INTEGERS = [0, 10, -10]
FLOATS = NUMERIC_FLOATS + FLOAT_STRINGS
INTEGERS = NUMERIC_INTEGERS + INTEGER_STRINGS
BIGDECIMAL = BIGDECIMAL_STRINGS.collect! { |bd| BigDecimal(bd) }
JUNK = ["not a number", "42 not a number", "0xdeadbeef", "-0xdeadbeef", "+0xdeadbeef", "0xinvalidhex", "0Xdeadbeef", "00-1", "--3", "+-3", "+3-1", "-+019.0", "12.12.13.12", "123\nnot a number"]
INFINITY = [1.0 / 0.0]
Expand Down Expand Up @@ -74,6 +76,20 @@ def test_validates_numericality_of_with_integer_only_and_proc_as_value
assert_valid_values(FLOATS + INTEGERS + BIGDECIMAL + INFINITY)
end

def test_validates_numericality_of_with_numeric_only
Topic.validates_numericality_of :approved, only_numeric: true

assert_invalid_values(NIL + BLANK + JUNK + FLOAT_STRINGS + INTEGER_STRINGS)
assert_valid_values(NUMERIC_FLOATS + NUMERIC_INTEGERS + BIGDECIMAL + INFINITY)
end

def test_validates_numericality_of_with_numeric_only_and_nil_allowed
Topic.validates_numericality_of :approved, only_numeric: true, allow_nil: true

assert_invalid_values(JUNK + BLANK + FLOAT_STRINGS + INTEGER_STRINGS)
assert_valid_values(NIL + NUMERIC_FLOATS + NUMERIC_INTEGERS + BIGDECIMAL + INFINITY)
end

def test_validates_numericality_with_greater_than
Topic.validates_numericality_of :approved, greater_than: 10

Expand Down

0 comments on commit 13e5857

Please sign in to comment.