модуль ActiveModel::Validations::ClassMethods
Публичные методы экземпляров
# File activemodel/lib/active_model/validations.rb, line 282 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
# File activemodel/lib/active_model/validations.rb, line 246 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
# File activemodel/lib/active_model/validations.rb, line 160
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- Указывает метод, лямбда-выражение или строку для вызова, чтобы определить, должна ли происходить валидация (например,if: :allow_validation, илиif: Proc.new { |user| user.signup_step > 2 }). Метод, лямбда-выражение или строка должны возвращать или вычисляться до логического значенияtrueилиfalse. -
:unless- Указывает метод, лямбда-выражение или строку для вызова, чтобы определить, не должна ли происходить валидация (например,unless: :skip_validation, илиunless: Proc.new { |user| user.signup_step <= 2 }). Метод, лямбда-выражение или строка должны возвращать или вычисляться до логического значенияtrueилиfalse.
ПРИМЕЧАНИЕ: Вызов validate несколько раз для одного метода перезапишет предыдущие определения.
# 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- Указывает метод, лямбда-выражение или строку для вызова, чтобы определить, должна ли происходить валидация (например,if: :allow_validation, илиif: Proc.new { |user| user.signup_step > 2 }). Метод, лямбда-выражение или строка должны возвращать или вычисляться до логического значенияtrueилиfalse. -
:unless- Указывает метод, лямбда-выражение или строку для вызова, чтобы определить, не должна ли происходить валидация (например,unless: :skip_validation, илиunless: Proc.new { |user| user.signup_step <= 2 }). Метод, лямбда-выражение или строка должны возвращать или вычисляться до логического значения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
# 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
# File activemodel/lib/active_model/validations.rb, line 88 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- Указывает метод, лямбда-выражение или строку для вызова, чтобы определить, должна ли происходить валидация (например,if: :allow_validation, илиif: Proc.new { |user| user.signup_step > 2 }). Метод, лямбда-выражение или строка должны возвращать или вычисляться до логического значенияtrueилиfalse. -
:unless- Указывает метод, лямбда-выражение или строку для вызова, чтобы определить, не должна ли происходить валидация (например,unless: :skip_validation, илиunless: Proc.new { |user| user.signup_step <= 2 }). Метод, лямбда-выражение или строка должны возвращать или вычисляться до логического значенияtrueилиfalse.
# 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- Указывает метод, прок или строку для вызова, чтобы определить, должна ли выполняться проверка (например,if: :allow_validation, илиif: Proc.new { |user| user.signup_step > 2 }). Метод, прок или строка должны возвращать или оцениваться какtrueилиfalseзначение. -
:unless- Указывает метод, прок или строку для вызова, чтобы определить, не должна ли выполняться проверка (например,unless: :skip_validation, илиunless: Proc.new { |user| user.signup_step <= 2 }). Метод, прок или строка должны возвращать или оцениваться как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
# File activemodel/lib/active_model/validations.rb, line 204 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}>
# ]
# File activemodel/lib/active_model/validations.rb, line 266
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.