Skip to content

Commit

Permalink
Enhance ActiveModel length validation checks to catch unexpected options
Browse files Browse the repository at this point in the history
Collect the valid options to be a constant also extract the unexpected options and verify them to decide raise error or not
  • Loading branch information
RobertChang0722 committed Jul 22, 2024
1 parent b291408 commit 4dad354
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 5 deletions.
16 changes: 11 additions & 5 deletions activemodel/lib/active_model/validations/length.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ class LengthValidator < EachValidator # :nodoc:
MESSAGES = { is: :wrong_length, minimum: :too_short, maximum: :too_long }.freeze
CHECKS = { is: :==, minimum: :>=, maximum: :<= }.freeze

RESERVED_OPTIONS = [:minimum, :maximum, :within, :is, :too_short, :too_long]
RESERVED_OPTIONS = [:minimum, :maximum, :within, :is, :too_short, :too_long, :wrong_length]

VALID_OPTIONS = CHECKS.keys +
RESERVED_OPTIONS +
ActiveModel::Error::CALLBACKS_OPTIONS +
ActiveModel::Error::MESSAGE_OPTIONS

def initialize(options)
if range = (options.delete(:in) || options.delete(:within))
Expand All @@ -27,15 +32,16 @@ def initialize(options)
end

def check_validity!
keys = CHECKS.keys & options.keys
keys = options.keys
unexpected_keys = keys - VALID_OPTIONS

if keys.empty?
length_keys = CHECKS.keys & keys
if length_keys.empty? || !unexpected_keys.empty?
raise ArgumentError, "Range unspecified. Specify the :in, :within, :maximum, :minimum, or :is option."
end

keys.each do |key|
length_keys.each do |key|
value = options[key]

unless (value.is_a?(Integer) && value >= 0) ||
value == Float::INFINITY || value == -Float::INFINITY ||
value.is_a?(Symbol) || value.is_a?(Proc)
Expand Down
5 changes: 5 additions & 0 deletions activemodel/test/cases/validations/length_validation_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -496,4 +496,9 @@ def test_validates_length_of_using_lambda_as_maximum
t.title = ""
assert_predicate t, :valid?
end
def test_typo_in_length_options_raises_error
assert_raise(ArgumentError) { Topic.validates_length_of :title, minium: 5, maximum: 10 }
assert_raise(ArgumentError) { Topic.validates_length_of :title, mimum: 5, maximum: 10 }
assert_raise(ArgumentError) { Topic.validates_length_of :title, mimum: 5, maxium: 10 }
end
end

0 comments on commit 4dad354

Please sign in to comment.