Check for out of range float values

Remove unsupported attribute `[maxlength]` from `input[number]`.
This commit is contained in:
2026-07-20 16:39:35 +02:00
parent ef8214cfa7
commit 5d051de666
10 changed files with 88 additions and 38 deletions

View File

@@ -0,0 +1,13 @@
module CoreExt::ActiveModel::Validations::NumericalityValidatesPrecision
def validate_each(record, attr_name, value, **kwargs)
super(record, attr_name, value, **kwargs)
# Check if value can be represented using Float data type.
# BigDecimal is used as a reference due to its arbitrary precision.
if record.class.type_for_attribute(attr_name).type == :float && !value.is_a?(Float)
unless value.to_d == value.to_f.to_d(kwargs[:precision])
record.errors.add(attr_name, :out_of_range, **filtered_options(value))
end
end
end
end

View File

@@ -1,19 +0,0 @@
module CoreExt::ActiveModel::Validations::NumericalityValidatesPrecisionAndScale
def validate_each(record, attr_name, value, ...)
super(record, attr_name, value, ...)
if options[:precision] || options[:scale]
attr_type = record.class.type_for_attribute(attr_name)
# For conversion of 'value' to BigDecimal 'ndigits' is not supplied intentionally,
# to avoid silent rounding. It is only required for conversion from Float and
# Rational, which should not happen.
value = BigDecimal(value) unless value.is_a? BigDecimal
if options[:precision] && (value.precision > attr_type.precision)
record.errors.add(attr_name, :precision_exceeded, **filtered_options(attr_type.precision))
end
if options[:scale] && (value.scale > attr_type.scale)
record.errors.add(attr_name, :scale_exceeded, **filtered_options(attr_type.scale))
end
end
end
end

View File

@@ -50,5 +50,6 @@ class Float
# TODO: change MIN_15 to MIN.ceil(MIN_10_EXP - DIG) after #ceil fix in Ruby
# v4.0.5: https://bugs.ruby-lang.org/issues/22079
MIN_15 = MIN.ceil(-(MIN_10_EXP - 1))
MAX_15 = MAX.floor(-(MAX_10_EXP - DIG + 1))
# MAX is an integer.
MAX_15 = MAX.floor(-(MAX_10_EXP - DIG + 1)).to_f
end