跳至内容 跳至搜索
方法
A
C
V

实例公共方法

attribute_method?(attribute)

如果 attribute 是属性方法,则返回 true,否则返回 false

class Person
  include ActiveModel::Validations

  attr_accessor :name
end

User.attribute_method?(:name) # => true
User.attribute_method?(:age)  # => false
# File activemodel/lib/active_model/validations.rb, line 284
def attribute_method?(attribute)
  method_defined?(attribute)
end

clear_validators!()

清除所有验证器和验证。

请注意,这将清除用于验证 validates_withvalidate 方法的模型的所有内容。它会清除使用 validates_with 调用创建的验证器,以及使用 validate 调用设置的回调。

class Person
  include ActiveModel::Validations

  validates_with MyValidator
  validates_with OtherValidator, on: :create
  validates_with StrictValidator, strict: true
  validate :cannot_be_robot

  def cannot_be_robot
    errors.add(:base, 'A person cannot be a robot') if person_is_robot
  end
end

Person.validators
# => [
#      #<MyValidator:0x007fbff403e808 @options={}>,
#      #<OtherValidator:0x007fbff403d930 @options={on: :create}>,
#      #<StrictValidator:0x007fbff3204a30 @options={strict:true}>
#    ]

如果运行 Person.clear_validators!,然后检查此类有哪些验证器,你将获得

Person.validators # => []

此外,由 validate :cannot_be_robot 设置的回调将被擦除,以便

Person._validate_callbacks.empty?  # => true
# File activemodel/lib/active_model/validations.rb, line 248
def clear_validators!
  reset_callbacks(:validate)
  _validators.clear
end

validate(*args, &block)

向类中添加验证方法或块。当覆盖 validate 实例方法变得过于繁琐,并且您正在寻找更具描述性的验证声明时,这非常有用。

可以使用指向方法的符号来完成此操作

class Comment
  include ActiveModel::Validations

  validate :must_be_friends

  def must_be_friends
    errors.add(:base, 'Must be friends to leave a comment') unless commenter.friend_of?(commentee)
  end
end

使用一个块,该块会传递给要验证的当前记录

class Comment
  include ActiveModel::Validations

  validate do |comment|
    comment.must_be_friends
  end

  def must_be_friends
    errors.add(:base, 'Must be friends to leave a comment') unless commenter.friend_of?(commentee)
  end
end

或者使用一个块,其中 self 指向要验证的当前记录

class Comment
  include ActiveModel::Validations

  validate do
    errors.add(:base, 'Must be friends to leave a comment') unless commenter.friend_of?(commentee)
  end
end

请注意,验证方法的返回值无关紧要。无法停止验证回调链。

选项

  • :on - 指定此验证处于活动状态的上下文。默认情况下在所有验证上下文中运行 nil。您可以传递一个符号或一个符号数组。(例如 on: :createon: :custom_validation_contexton: [:create, :custom_validation_context]

  • :if - 指定一个方法、过程或字符串,以调用它来确定是否应进行验证(例如 if: :allow_validation,或 if: Proc.new { |user| user.signup_step > 2 })。该方法、过程或字符串应返回或评估为 truefalse 值。

  • :unless - 指定一个方法、过程或字符串,以调用它来确定是否不应进行验证(例如 unless: :skip_validation,或 unless: Proc.new { |user| user.signup_step <= 2 })。该方法、过程或字符串应返回或评估为 truefalse 值。

注意:对同一方法多次调用 validate 将覆盖以前的定义。

# File activemodel/lib/active_model/validations.rb, line 171
def validate(*args, &block)
  options = args.extract_options!

  if args.all?(Symbol)
    options.each_key do |k|
      unless VALID_OPTIONS_FOR_VALIDATE.include?(k)
        raise ArgumentError.new("Unknown key: #{k.inspect}. Valid keys are: #{VALID_OPTIONS_FOR_VALIDATE.map(&:inspect).join(', ')}. Perhaps you meant to call `validates` instead of `validate`?")
      end
    end
  end

  if options.key?(:on)
    options = options.merge(if: [predicate_for_validation_context(options[:on]), *options[:if]])
  end

  set_callback(:validate, *args, options, &block)
end

validates(*attributes)

此方法是所有默认验证器和以“Validator”结尾的任何自定义验证器类的快捷方式。请注意,可以通过创建自定义验证器类(例如 PresenceValidator)来覆盖特定类中的 Rails 默认验证器。

使用默认 Rails 验证器的示例

validates :username, absence: true
validates :terms, acceptance: true
validates :password, confirmation: true
validates :username, exclusion: { in: %w(admin superuser) }
validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, on: :create }
validates :age, inclusion: { in: 0..9 }
validates :first_name, length: { maximum: 30 }
validates :age, numericality: true
validates :username, presence: true

validates 方法的强大之处在于,在一个给定属性的调用中使用自定义验证器和默认验证器。

class EmailValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    record.errors.add attribute, (options[:message] || "is not an email") unless
      /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i.match?(value)
  end
end

class Person
  include ActiveModel::Validations
  attr_accessor :name, :email

  validates :name, presence: true, length: { maximum: 100 }
  validates :email, presence: true, email: true
end

Validator 类也可能存在于正在验证的类中,允许根据需要包含验证器的自定义模块。

class Film
  include ActiveModel::Validations

  class TitleValidator < ActiveModel::EachValidator
    def validate_each(record, attribute, value)
      record.errors.add attribute, "must start with 'the'" unless /\Athe/i.match?(value)
    end
  end

  validates :name, title: true
end

此外,验证器类可能在另一个命名空间中,并且仍然在任何类中使用。

validates :name, :'film/title' => true

验证器哈希还可以处理正则表达式、范围、数组和字符串的快捷方式。

validates :email, format: /@/
validates :role, inclusion: %w(admin contributor)
validates :password, length: 6..20

使用快捷方式时,范围和数组将作为 options[:in] 传递给验证器的初始化程序,而包括正则表达式和字符串在内的其他类型将作为 options[:with] 传递。

还有一系列选项可以与验证器一起使用

  • :on - 指定此验证处于活动状态的上下文。默认情况下在所有验证上下文中运行 nil。您可以传递一个符号或一个符号数组。(例如 on: :createon: :custom_validation_contexton: [:create, :custom_validation_context]

  • :if - 指定一个方法、过程或字符串,以调用它来确定是否应进行验证(例如 if: :allow_validation,或 if: Proc.new { |user| user.signup_step > 2 })。该方法、过程或字符串应返回或评估为 truefalse 值。

  • :unless - 指定一个方法、过程或字符串,以调用它来确定是否不应进行验证(例如 unless: :skip_validation,或 unless: Proc.new { |user| user.signup_step <= 2 })。该方法、过程或字符串应返回或评估为 truefalse 值。

  • :allow_nil - 如果属性为 nil,则跳过验证。

  • :allow_blank - 如果属性为空,则跳过验证。

  • :strict - 如果 :strict 选项设置为 true,则将引发 ActiveModel::StrictValidationFailed,而不是添加错误。:strict 选项也可以设置为任何其他异常。

示例

validates :password, presence: true, confirmation: true, if: :password_required?
validates :token, length: { is: 24 }, strict: TokenLengthException

最后,选项 :if:unless:on:allow_blank:allow_nil:strict:message 可以作为哈希传递给一个特定验证器

validates :password, presence: { if: :password_required?, message: 'is forgotten.' }, confirmation: true
# File activemodel/lib/active_model/validations/validates.rb, line 106
def validates(*attributes)
  defaults = attributes.extract_options!.dup
  validations = defaults.slice!(*_validates_default_keys)

  raise ArgumentError, "You need to supply at least one attribute" if attributes.empty?
  raise ArgumentError, "You need to supply at least one validation" if validations.empty?

  defaults[:attributes] = attributes

  validations.each do |key, options|
    key = "#{key.to_s.camelize}Validator"

    begin
      validator = const_get(key)
    rescue NameError
      raise ArgumentError, "Unknown validator: '#{key}'"
    end

    next unless options

    validates_with(validator, defaults.merge(_parse_validates_options(options)))
  end
end

validates!(*attributes)

此方法用于定义无法由最终用户更正且被视为异常的验证。因此,使用感叹号或将 :strict 选项设置为 true 定义的每个验证器在验证失败时始终会引发 ActiveModel::StrictValidationFailed,而不是添加错误。有关验证本身的更多信息,请参阅 validates

class Person
  include ActiveModel::Validations

  attr_accessor :name
  validates! :name, presence: true
end

person = Person.new
person.name = ''
person.valid?
# => ActiveModel::StrictValidationFailed: Name can't be blank
# File activemodel/lib/active_model/validations/validates.rb, line 148
def validates!(*attributes)
  options = attributes.extract_options!
  options[:strict] = true
  validates(*(attributes << options))
end

validates_each(*attr_names, &block)

根据块验证每个属性。

class Person
  include ActiveModel::Validations

  attr_accessor :first_name, :last_name

  validates_each :first_name, :last_name, allow_blank: true do |record, attr, value|
    record.errors.add attr, "starts with z." if value.start_with?("z")
  end
end

选项

  • :on - 指定此验证处于活动状态的上下文。默认情况下在所有验证上下文中运行 nil。您可以传递一个符号或一个符号数组。(例如 on: :createon: :custom_validation_contexton: [:create, :custom_validation_context]

  • :allow_nil - 如果属性为 nil,则跳过验证。

  • :allow_blank - 如果属性为空,则跳过验证。

  • :if - 指定一个方法、过程或字符串,以调用它来确定是否应进行验证(例如 if: :allow_validation,或 if: Proc.new { |user| user.signup_step > 2 })。该方法、过程或字符串应返回或评估为 truefalse 值。

  • :unless - 指定一个方法、过程或字符串,以调用它来确定是否不应进行验证(例如 unless: :skip_validation,或 unless: Proc.new { |user| user.signup_step <= 2 })。该方法、过程或字符串应返回或评估为 truefalse 值。

# File activemodel/lib/active_model/validations.rb, line 104
def validates_each(*attr_names, &block)
  validates_with BlockValidator, _merge_attributes(attr_names), &block
end

validates_with(*args, &block)

将记录传递到指定的类或类,并允许它们根据更复杂的条件添加错误。

class Person
  include ActiveModel::Validations
  validates_with MyValidator
end

class MyValidator < ActiveModel::Validator
  def validate(record)
    if some_complex_logic
      record.errors.add :base, 'This record is invalid'
    end
  end

  private
    def some_complex_logic
      # ...
    end
end

您还可以像这样传递多个类

class Person
  include ActiveModel::Validations
  validates_with MyValidator, MyOtherValidator, on: :create
end

validates_with 没有默认错误消息。您必须在验证器类中手动将错误添加到记录的错误集合中。

要实现 validate 方法,您必须定义一个 record 参数,它是待验证的记录。

配置选项

  • :on - 指定此验证处于活动状态的上下文。默认情况下在所有验证上下文中运行 nil。您可以传递一个符号或一个符号数组。(例如 on: :createon: :custom_validation_contexton: [:create, :custom_validation_context]

  • :if - 指定一个方法、过程或字符串来调用,以确定是否应进行验证(例如 if: :allow_validationif: Proc.new { |user| user.signup_step > 2 })。方法、过程或字符串应返回或评估为 truefalse 值。

  • :unless - 指定一个方法、过程或字符串,以调用它来确定是否不应进行验证(例如 unless: :skip_validation,或 unless: Proc.new { |user| user.signup_step <= 2 })。该方法、过程或字符串应返回或评估为 truefalse 值。

  • :strict - 指定验证是否应严格。有关更多信息,请参见 ActiveModel::Validations#validates!

如果您传递任何其他配置选项,它们将传递给类并作为 options 提供

class Person
  include ActiveModel::Validations
  validates_with MyValidator, my_custom_key: 'my custom value'
end

class MyValidator < ActiveModel::Validator
  def validate(record)
    options[:my_custom_key] # => "my custom value"
  end
end
# File activemodel/lib/active_model/validations/with.rb, line 88
def validates_with(*args, &block)
  options = args.extract_options!
  options[:class] = self

  args.each do |klass|
    validator = klass.new(options.dup, &block)

    if validator.respond_to?(:attributes) && !validator.attributes.empty?
      validator.attributes.each do |attribute|
        _validators[attribute.to_sym] << validator
      end
    else
      _validators[nil] << validator
    end

    validate(validator, options)
  end
end

validators()

列出所有用于使用 validates_with 方法验证模型的验证器。

class Person
  include ActiveModel::Validations

  validates_with MyValidator
  validates_with OtherValidator, on: :create
  validates_with StrictValidator, strict: true
end

Person.validators
# => [
#      #<MyValidator:0x007fbff403e808 @options={}>,
#      #<OtherValidator:0x007fbff403d930 @options={on: :create}>,
#      #<StrictValidator:0x007fbff3204a30 @options={strict:true}>
#    ]
# File activemodel/lib/active_model/validations.rb, line 206
def validators
  _validators.values.flatten.uniq
end

validators_on(*attributes)

列出用于验证特定属性的所有验证器。

class Person
  include ActiveModel::Validations

  attr_accessor :name, :age

  validates_presence_of :name
  validates_inclusion_of :age, in: 0..99
end

Person.validators_on(:name)
# => [
#       #<ActiveModel::Validations::PresenceValidator:0x007fe604914e60 @attributes=[:name], @options={}>,
#    ]
# File activemodel/lib/active_model/validations.rb, line 268
def validators_on(*attributes)
  attributes.flat_map do |attribute|
    _validators[attribute.to_sym]
  end
end