check for valid options in validate method

This change prevents a certain class of user error which results when
mistakenly using the `validate` class method instead of the `validates`
class method.

Only apply when all arguments are symbols, because some validations use
the `validate` method and pass in additional options, namely the
`LenghValidator` via the `ActiveMode::Validations::validates_with`
method.
This commit is contained in:
sonnym 2014-07-17 17:02:54 -04:00
parent 932386be8a
commit 0950d409b0
3 changed files with 18 additions and 0 deletions

View File

@ -1,3 +1,9 @@
* Validate options passed to `ActiveModel::Validations::validate`
Preventing, in many cases, the simple mistake of using `validate` instead of `validate`.
*Sonny Michaud*
* Deprecate `reset_#{attribute}` in favor of `restore_#{attribute}`. * Deprecate `reset_#{attribute}` in favor of `restore_#{attribute}`.
These methods may cause confusion with the `reset_changes` that behaves differently These methods may cause confusion with the `reset_changes` that behaves differently

View File

@ -141,6 +141,11 @@ module ActiveModel
# value. # value.
def validate(*args, &block) def validate(*args, &block)
options = args.extract_options! options = args.extract_options!
if args.all? { |arg| arg.is_a?(Symbol) }
options.assert_valid_keys(%i(on if unless))
end
if options.key?(:on) if options.key?(:on)
options = options.dup options = options.dup
options[:if] = Array(options[:if]) options[:if] = Array(options[:if])
@ -148,6 +153,7 @@ module ActiveModel
Array(options[:on]).include?(o.validation_context) Array(options[:on]).include?(o.validation_context)
} }
end end
args << options args << options
set_callback(:validate, *args, &block) set_callback(:validate, *args, &block)
end end

View File

@ -167,6 +167,12 @@ class ValidationsTest < ActiveModel::TestCase
end end
end end
def test_invalid_options_to_validate
assert_raises(ArgumentError) do
Topic.validate :title, presence: true
end
end
def test_errors_conversions def test_errors_conversions
Topic.validates_presence_of %w(title content) Topic.validates_presence_of %w(title content)
t = Topic.new t = Topic.new