提交 7045c4c2 编写于 作者: J José Valim

Allow validates to map some types to specific options. So now you can do:

  validates :email, :presence => true, :format => /@/
  validates :genre, :inclusion => %w(m f)
  validates :password, :length => 6..20
上级 fa14d6d5
...@@ -10,9 +10,10 @@ def initialize(options) ...@@ -10,9 +10,10 @@ def initialize(options)
end end
def check_validity! def check_validity!
options.slice(*CHECKS.keys) do |option, value| keys = CHECKS.keys - [:odd, :event]
next if [:odd, :even].include?(option) options.slice(*keys) do |option, value|
raise ArgumentError, ":#{option} must be a number, a symbol or a proc" unless value.is_a?(Numeric) || value.is_a?(Proc) || value.is_a?(Symbol) next if value.is_a?(Numeric) || value.is_a?(Proc) || value.is_a?(Symbol)
raise ArgumentError, ":#{option} must be a number, a symbol or a proc"
end end
end end
......
...@@ -7,6 +7,7 @@ module ClassMethods ...@@ -7,6 +7,7 @@ module ClassMethods
# custom validator classes in their place such as PresenceValidator. # custom validator classes in their place such as PresenceValidator.
# #
# Examples of using the default rails validators: # Examples of using the default rails validators:
#
# validates :terms, :acceptance => true # validates :terms, :acceptance => true
# validates :password, :confirmation => true # validates :password, :confirmation => true
# validates :username, :exclusion => { :in => %w(admin superuser) } # validates :username, :exclusion => { :in => %w(admin superuser) }
...@@ -19,6 +20,7 @@ module ClassMethods ...@@ -19,6 +20,7 @@ module ClassMethods
# #
# The power of the +validates+ method comes when using cusom validators # The power of the +validates+ method comes when using cusom validators
# and default validators in one call for a given attribute e.g. # and default validators in one call for a given attribute e.g.
#
# class EmailValidator < ActiveModel::EachValidator # class EmailValidator < ActiveModel::EachValidator
# def validate_each(record, attribute, value) # def validate_each(record, attribute, value)
# record.errors[attribute] << (options[:message] || "is not an email") unless # record.errors[attribute] << (options[:message] || "is not an email") unless
...@@ -31,29 +33,32 @@ module ClassMethods ...@@ -31,29 +33,32 @@ module ClassMethods
# attr_accessor :name, :email # attr_accessor :name, :email
# #
# validates :name, :presence => true, :uniqueness => true, :length => { :maximum => 100 } # validates :name, :presence => true, :uniqueness => true, :length => { :maximum => 100 }
# validates :email, :presence => true, :format => { :with => /@/ } # validates :email, :presence => true, :email => true
# end # end
# #
# Validator classes my also exist within the class being validated # Validator classes my also exist within the class being validated
# allowing custom modules of validators to be included as needed e.g. # allowing custom modules of validators to be included as needed e.g.
# #
# module MyValidators # class Film
# include ActiveModel::Validations
#
# class TitleValidator < ActiveModel::EachValidator # class TitleValidator < ActiveModel::EachValidator
# def validate_each(record, attribute, value) # def validate_each(record, attribute, value)
# record.errors[attribute] << "must start with 'the'" unless =~ /^the/i # record.errors[attribute] << "must start with 'the'" unless =~ /^the/i
# end # end
# end # end
# end
#
# class Film
# include ActiveModel::Validations
# include MyValidators
# #
# validates :name, :title => true # validates :name, :title => true
# end # end
# #
# The options :if, :unless, :on, :allow_blank and :allow_nil can be given to one specific # The validators hash can also handle regular expressions, ranges and arrays:
# validator: #
# validates :email, :format => /@/
# validates :genre, :inclusion => %w(mail female)
# validates :password, :length => 6..20
#
# Finally, the options :if, :unless, :on, :allow_blank and :allow_nil can be given
# to one specific validator:
# #
# validates :password, :presence => { :if => :password_required? }, :confirmation => true # validates :password, :presence => { :if => :password_required? }, :confirmation => true
# #
...@@ -78,7 +83,22 @@ def validates(*attributes) ...@@ -78,7 +83,22 @@ def validates(*attributes)
raise ArgumentError, "Unknown validator: '#{key}'" raise ArgumentError, "Unknown validator: '#{key}'"
end end
validates_with(validator, defaults.merge(options == true ? {} : options)) validates_with(validator, defaults.merge(_parse_validates_options(options)))
end
end
protected
def _parse_validates_options(options) #:nodoc:
case options
when TrueClass
{}
when Hash
options
when Regexp
{ :with => options }
when Range, Array
{ :in => options }
end end
end end
end end
......
...@@ -10,43 +10,42 @@ class ValidatesTest < ActiveModel::TestCase ...@@ -10,43 +10,42 @@ class ValidatesTest < ActiveModel::TestCase
def reset_callbacks def reset_callbacks
Person.reset_callbacks(:validate) Person.reset_callbacks(:validate)
PersonWithValidator.reset_callbacks(:validate)
end end
def test_validates_with_built_in_validation def test_validates_with_built_in_validation
Person.validates :title, :numericality => true Person.validates :title, :numericality => true
person = Person.new person = Person.new
person.valid? person.valid?
assert person.errors[:title].include?('is not a number') assert_equal ['is not a number'], person.errors[:title]
end end
def test_validates_with_built_in_validation_and_options def test_validates_with_built_in_validation_and_options
Person.validates :title, :numericality => { :message => 'my custom message' } Person.validates :salary, :numericality => { :message => 'my custom message' }
person = Person.new person = Person.new
person.valid? person.valid?
assert person.errors[:title].include?('my custom message') assert_equal ['my custom message'], person.errors[:salary]
end end
def test_validates_with_validator_class def test_validates_with_validator_class
Person.validates :karma, :email => true Person.validates :karma, :email => true
person = Person.new person = Person.new
person.valid? person.valid?
assert person.errors[:karma].include?('is not an email') assert_equal ['is not an email'], person.errors[:karma]
end end
def test_validates_with_if_as_local_conditions def test_validates_with_if_as_local_conditions
Person.validates :karma, :presence => true, :email => { :unless => :condition_is_true } Person.validates :karma, :presence => true, :email => { :unless => :condition_is_true }
person = Person.new person = Person.new
person.valid? person.valid?
assert !person.errors[:karma].include?('is not an email') assert_equal ["can't be blank"], person.errors[:karma]
assert person.errors[:karma].include?('can\'t be blank')
end end
def test_validates_with_if_as_shared_conditions def test_validates_with_if_as_shared_conditions
Person.validates :karma, :presence => true, :email => true, :if => :condition_is_true Person.validates :karma, :presence => true, :email => true, :if => :condition_is_true
person = Person.new person = Person.new
person.valid? person.valid?
assert person.errors[:karma].include?('is not an email') assert ["can't be blank", "is not an email"], person.errors[:karma].sort
assert person.errors[:karma].include?('can\'t be blank')
end end
def test_validates_with_unless_shared_conditions def test_validates_with_unless_shared_conditions
...@@ -61,11 +60,38 @@ def test_validates_with_allow_nil_shared_conditions ...@@ -61,11 +60,38 @@ def test_validates_with_allow_nil_shared_conditions
assert person.valid? assert person.valid?
end end
def test_validates_with_regexp
Person.validates :karma, :format => /positive|negative/
person = Person.new
assert person.invalid?
assert_equal ['is invalid'], person.errors[:karma]
person.karma = "positive"
assert person.valid?
end
def test_validates_with_array
Person.validates :genre, :inclusion => %w(m f)
person = Person.new
assert person.invalid?
assert_equal ['is not included in the list'], person.errors[:genre]
person.genre = "m"
assert person.valid?
end
def test_validates_with_range
Person.validates :password, :length => 6..20
person = Person.new
assert person.invalid?
assert_equal ['is too short (minimum is 6 characters)'], person.errors[:password]
person.password = '123456'
assert person.valid?
end
def test_validates_with_validator_class_and_options def test_validates_with_validator_class_and_options
Person.validates :karma, :email => { :message => 'my custom message' } Person.validates :karma, :email => { :message => 'my custom message' }
person = Person.new person = Person.new
person.valid? person.valid?
assert person.errors[:karma].include?('my custom message') assert_equal ['my custom message'], person.errors[:karma]
end end
def test_validates_with_unknown_validator def test_validates_with_unknown_validator
...@@ -76,13 +102,13 @@ def test_validates_with_included_validator ...@@ -76,13 +102,13 @@ def test_validates_with_included_validator
PersonWithValidator.validates :title, :presence => true PersonWithValidator.validates :title, :presence => true
person = PersonWithValidator.new person = PersonWithValidator.new
person.valid? person.valid?
assert person.errors[:title].include?('Local validator') assert_equal ['Local validator'], person.errors[:title]
end end
def test_validates_with_included_validator_and_options def test_validates_with_included_validator_and_options
PersonWithValidator.validates :title, :presence => { :custom => ' please' } PersonWithValidator.validates :title, :presence => { :custom => ' please' }
person = PersonWithValidator.new person = PersonWithValidator.new
person.valid? person.valid?
assert person.errors[:title].include?('Local validator please') assert_equal ['Local validator please'], person.errors[:title]
end end
end end
\ No newline at end of file
...@@ -2,7 +2,7 @@ class Person ...@@ -2,7 +2,7 @@ class Person
include ActiveModel::Validations include ActiveModel::Validations
extend ActiveModel::Translation extend ActiveModel::Translation
attr_accessor :title, :karma, :salary attr_accessor :title, :karma, :salary, :genre, :password
def condition_is_true def condition_is_true
true true
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册