Add validate numericality in range
This commit is contained in:
parent
c28c800803
commit
2486e887de
|
@ -1,3 +1,7 @@
|
||||||
|
* Add `in: range` parameter to `numericality` validator.
|
||||||
|
|
||||||
|
*Michal Papis*
|
||||||
|
|
||||||
* Add `locale` argument to `ActiveModel::Name#initialize` to be used to generate the `singular`,
|
* Add `locale` argument to `ActiveModel::Name#initialize` to be used to generate the `singular`,
|
||||||
`plural`, `route_key` and `singular_route_key` values.
|
`plural`, `route_key` and `singular_route_key` values.
|
||||||
|
|
||||||
|
|
|
@ -32,5 +32,6 @@ en:
|
||||||
less_than: "must be less than %{count}"
|
less_than: "must be less than %{count}"
|
||||||
less_than_or_equal_to: "must be less than or equal to %{count}"
|
less_than_or_equal_to: "must be less than or equal to %{count}"
|
||||||
other_than: "must be other than %{count}"
|
other_than: "must be other than %{count}"
|
||||||
|
in: "must be in %{count}"
|
||||||
odd: "must be odd"
|
odd: "must be odd"
|
||||||
even: "must be even"
|
even: "must be even"
|
||||||
|
|
|
@ -7,7 +7,7 @@ module ActiveModel
|
||||||
class NumericalityValidator < EachValidator # :nodoc:
|
class NumericalityValidator < EachValidator # :nodoc:
|
||||||
CHECKS = { greater_than: :>, greater_than_or_equal_to: :>=,
|
CHECKS = { greater_than: :>, greater_than_or_equal_to: :>=,
|
||||||
equal_to: :==, less_than: :<, less_than_or_equal_to: :<=,
|
equal_to: :==, less_than: :<, less_than_or_equal_to: :<=,
|
||||||
odd: :odd?, even: :even?, other_than: :!= }.freeze
|
odd: :odd?, even: :even?, other_than: :!=, in: :in? }.freeze
|
||||||
|
|
||||||
RESERVED_OPTIONS = CHECKS.keys + [:only_integer]
|
RESERVED_OPTIONS = CHECKS.keys + [:only_integer]
|
||||||
|
|
||||||
|
@ -16,12 +16,17 @@ module ActiveModel
|
||||||
HEXADECIMAL_REGEX = /\A[+-]?0[xX]/
|
HEXADECIMAL_REGEX = /\A[+-]?0[xX]/
|
||||||
|
|
||||||
def check_validity!
|
def check_validity!
|
||||||
keys = CHECKS.keys - [:odd, :even]
|
keys = CHECKS.keys - [:odd, :even, :in]
|
||||||
options.slice(*keys).each do |option, value|
|
options.slice(*keys).each do |option, value|
|
||||||
unless value.is_a?(Numeric) || value.is_a?(Proc) || value.is_a?(Symbol)
|
unless value.is_a?(Numeric) || value.is_a?(Proc) || value.is_a?(Symbol)
|
||||||
raise ArgumentError, ":#{option} must be a number, a symbol or a proc"
|
raise ArgumentError, ":#{option} must be a number, a symbol or a proc"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
options.slice(:in).each do |option, value|
|
||||||
|
unless value.is_a?(Range)
|
||||||
|
raise ArgumentError, ":#{option} must be a range"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_each(record, attr_name, value, precision: Float::DIG, scale: nil)
|
def validate_each(record, attr_name, value, precision: Float::DIG, scale: nil)
|
||||||
|
@ -51,7 +56,7 @@ module ActiveModel
|
||||||
option_value = record.send(option_value)
|
option_value = record.send(option_value)
|
||||||
end
|
end
|
||||||
|
|
||||||
option_value = parse_as_number(option_value, precision, scale)
|
option_value = parse_as_number(option_value, precision, scale, option)
|
||||||
|
|
||||||
unless value.public_send(CHECKS[option], option_value)
|
unless value.public_send(CHECKS[option], option_value)
|
||||||
record.errors.add(attr_name, option, **filtered_options(value).merge!(count: option_value))
|
record.errors.add(attr_name, option, **filtered_options(value).merge!(count: option_value))
|
||||||
|
@ -61,8 +66,10 @@ module ActiveModel
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def parse_as_number(raw_value, precision, scale)
|
def parse_as_number(raw_value, precision, scale, option = nil)
|
||||||
if raw_value.is_a?(Float)
|
if option == :in
|
||||||
|
raw_value if raw_value.is_a?(Range)
|
||||||
|
elsif raw_value.is_a?(Float)
|
||||||
parse_float(raw_value, precision, scale)
|
parse_float(raw_value, precision, scale)
|
||||||
elsif raw_value.is_a?(Numeric)
|
elsif raw_value.is_a?(Numeric)
|
||||||
raw_value
|
raw_value
|
||||||
|
|
|
@ -7,6 +7,7 @@ require "models/person"
|
||||||
|
|
||||||
require "bigdecimal"
|
require "bigdecimal"
|
||||||
require "active_support/core_ext/big_decimal"
|
require "active_support/core_ext/big_decimal"
|
||||||
|
require "active_support/core_ext/object/inclusion"
|
||||||
|
|
||||||
class NumericalityValidationTest < ActiveModel::TestCase
|
class NumericalityValidationTest < ActiveModel::TestCase
|
||||||
def teardown
|
def teardown
|
||||||
|
@ -206,6 +207,13 @@ class NumericalityValidationTest < ActiveModel::TestCase
|
||||||
valid!([-1, 42])
|
valid!([-1, 42])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_validates_numericality_with_in
|
||||||
|
Topic.validates_numericality_of :approved, in: 1..3
|
||||||
|
|
||||||
|
invalid!([0, 4])
|
||||||
|
valid!([1, 2, 3])
|
||||||
|
end
|
||||||
|
|
||||||
def test_validates_numericality_with_other_than_using_string_value
|
def test_validates_numericality_with_other_than_using_string_value
|
||||||
Topic.validates_numericality_of :approved, other_than: 0
|
Topic.validates_numericality_of :approved, other_than: 0
|
||||||
|
|
||||||
|
|
|
@ -528,6 +528,8 @@ constraints to acceptable values:
|
||||||
less than or equal to %{count}"_.
|
less than or equal to %{count}"_.
|
||||||
* `:other_than` - Specifies the value must be other than the supplied value.
|
* `:other_than` - Specifies the value must be other than the supplied value.
|
||||||
The default error message for this option is _"must be other than %{count}"_.
|
The default error message for this option is _"must be other than %{count}"_.
|
||||||
|
* `:in` - Specifies the value must be in the supplied range.
|
||||||
|
The default error message for this option is _"must be in %{count}"_.
|
||||||
* `:odd` - Specifies the value must be an odd number if set to true. The
|
* `:odd` - Specifies the value must be an odd number if set to true. The
|
||||||
default error message for this option is _"must be odd"_.
|
default error message for this option is _"must be odd"_.
|
||||||
* `:even` - Specifies the value must be an even number if set to true. The
|
* `:even` - Specifies the value must be an even number if set to true. The
|
||||||
|
|
|
@ -993,6 +993,7 @@ So, for example, instead of the default error message `"cannot be blank"` you co
|
||||||
| numericality | :less_than_or_equal_to | :less_than_or_equal_to | count |
|
| numericality | :less_than_or_equal_to | :less_than_or_equal_to | count |
|
||||||
| numericality | :other_than | :other_than | count |
|
| numericality | :other_than | :other_than | count |
|
||||||
| numericality | :only_integer | :not_an_integer | - |
|
| numericality | :only_integer | :not_an_integer | - |
|
||||||
|
| numericality | :in | :in | count |
|
||||||
| numericality | :odd | :odd | - |
|
| numericality | :odd | :odd | - |
|
||||||
| numericality | :even | :even | - |
|
| numericality | :even | :even | - |
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue