Spec-Zone.ru › Ruby on Rails 8.1

модуль ActiveModel::Validations::ClassMethods

Открытые методы экземпляра

attribute_method? (attribute) Показать исходный код
# File activemodel/lib/active_model/validations.rb, line 284
def attribute_method?(attribute)
  method_defined?(attribute)
end

Возвращает true, если attribute является методом атрибута, и false в противном случае.

class Person
  include ActiveModel::Validations

  attr_accessor :name
end

User.attribute_method?(:name) # => true
User.attribute_method?(:age)  # => false
clear_validators! () Показать исходный код
# File activemodel/lib/active_model/validations.rb, line 248
def clear_validators!
  reset_callbacks(:validate)
  _validators.clear
end

Удаляет все валидаторы и правила валидации.

Обратите внимание: это удалит все средства, используемые для валидации модели, как для методов validates_with, так и для validate. Удаляются валидаторы, созданные вызовом 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
validate (*args, &block) Показать исходный код
# File activemodel/lib/active_model/validations.rb, line 162
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

  if options.key?(:except_on)
    options = options.dup
    options[:except_on] = Array(options[:except_on])
    options[:unless] = [
      ->(o) { options[:except_on].intersect?(Array(o.validation_context)) },
      *options[:unless]
    ]
  end

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

Добавляет в класс метод или блок валидации. Это полезно, если переопределение метода экземпляра 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: :create, on: :custom_validation_context или on: [:create, :custom_validation_context]).

  • :except_on — задаёт контексты, в которых эта валидация не активна. По умолчанию она выполняется во всех контекстах валидации nil. Можно передать символ или массив символов (например, except: :create, except_on: :custom_validation_context или except_on: [:create, :custom_validation_context]).

  • :if — задаёт метод или proc, который нужно вызвать, чтобы определить, следует ли выполнять валидацию (например, if: :allow_validation или if: Proc.new { |user| user.signup_step > 2 }). Метод или proc должен возвращать или вычисляться в значение true или false.

  • :unless — задаёт метод или proc, который нужно вызвать, чтобы определить, не следует ли выполнять валидацию (например, unless: :skip_validation или unless: Proc.new { |user| user.signup_step <= 2 }). Метод или proc должен возвращать или вычисляться в значение true или false.

ПРИМЕЧАНИЕ: повторный вызов validate для того же метода перезапишет предыдущие определения.

validates (*attributes) Показать исходный код
# File activemodel/lib/active_model/validations/validates.rb, line 111
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

Этот метод служит сокращённой записью для всех стандартных валидаторов и любых пользовательских классов валидаторов, оканчивающихся на «Validator». Обратите внимание: стандартные валидаторы Rails можно переопределить для отдельных классов, создав вместо них пользовательские классы валидаторов, например PresenceValidator.

Примеры использования стандартных валидаторов 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: :create, on: :custom_validation_context или on: [:create, :custom_validation_context]).

  • :except_on — задаёт контексты, в которых эта валидация не активна. По умолчанию она выполняется во всех контекстах валидации nil. Можно передать символ или массив символов (например, except: :create, except_on: :custom_validation_context или except_on: [:create, :custom_validation_context]).

  • :if — задаёт метод, proc или строку, которые нужно вызвать, чтобы определить, следует ли выполнять валидацию (например, if: :allow_validation или if: Proc.new { |user| user.signup_step > 2 }). Метод, proc или строка должны возвращать или вычисляться в значение true или false.

  • :unless — задаёт метод, proc или строку, которые нужно вызвать, чтобы определить, не следует ли выполнять валидацию (например, unless: :skip_validation или unless: Proc.new { |user| user.signup_step <= 2 }). Метод, proc или строка должны возвращать или вычисляться в значение true или false.

  • :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
validates! (*attributes) Показать исходный код
# File activemodel/lib/active_model/validations/validates.rb, line 153
def validates!(*attributes)
  options = attributes.extract_options!
  options[:strict] = true
  validates(*(attributes << options))
end

Этот метод используется для определения правил валидации, которые конечные пользователи не могут исправить и которые считаются исключительными. Поэтому каждый валидатор, заданный с помощью восклицательного знака или параметра :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
validates_each (*attr_names, &block) Показать исходный код
# File activemodel/lib/active_model/validations.rb, line 89
def validates_each(*attr_names, &block)
  validates_with BlockValidator, _merge_attributes(attr_names), &block
end

Проверяет каждый атрибут с помощью блока.

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: :create, on: :custom_validation_context или on: [:create, :custom_validation_context]).

  • :except_on — задаёт контексты, в которых эта валидация не активна. По умолчанию она выполняется во всех контекстах валидации nil. Можно передать символ или массив символов (например, except: :create, except_on: :custom_validation_context или except_on: [:create, :custom_validation_context]).

  • :allow_nil — пропустить валидацию, если атрибут имеет значение nil.

  • :allow_blank — пропустить валидацию, если атрибут пуст.

  • :if — задаёт метод, proc или строку, которые нужно вызвать, чтобы определить, следует ли выполнять валидацию (например, if: :allow_validation или if: Proc.new { |user| user.signup_step > 2 }). Метод, proc или строка должны возвращать или вычисляться в значение true или false.

  • :unless — задаёт метод, proc или строку, которые нужно вызвать, чтобы определить, не следует ли выполнять валидацию (например, unless: :skip_validation или unless: Proc.new { |user| user.signup_step <= 2 }). Метод, proc или строка должны возвращать или вычисляться в значение true или false.

validates_with (*args, &block) Показать исходный код
# 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

Передаёт запись указанному классу или классам и позволяет им добавлять ошибки на основании более сложных условий.

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: :create, on: :custom_validation_context или on: [:create, :custom_validation_context]).

  • :if — задаёт метод, proc или строку, которые нужно вызвать, чтобы определить, следует ли выполнять валидацию (например, if: :allow_validation или if: Proc.new { |user| user.signup_step > 2 }). Метод, proc или строка должны возвращать или вычисляться в значение true или false.

  • :unless — задаёт метод, proc или строку, которые нужно вызвать, чтобы определить, не следует ли выполнять валидацию (например, unless: :skip_validation или unless: Proc.new { |user| user.signup_step <= 2 }). Метод, proc или строка должны возвращать или вычисляться в значение true или false.

  • :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
validators () Показать исходный код
# File activemodel/lib/active_model/validations.rb, line 206
def validators
  _validators.values.flatten.uniq
end

Список всех валидаторов, используемых для валидации модели с помощью метода 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}>
#    ]
validators_on (*attributes) Показать исходный код
# File activemodel/lib/active_model/validations.rb, line 268
def validators_on(*attributes)
  attributes.flat_map do |attribute|
    _validators[attribute.to_sym]
  end
end

Список всех валидаторов, используемых для валидации указанного атрибута.

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={}>,
#    ]

© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API