跳至内容 跳至搜索

Active Model Errors

提供与错误相关的功能,您可以将其包含在您的对象中,用于处理错误消息和与 Action View 助手进行交互。

一个最小化的实现可以是

class Person
  # Required dependency for ActiveModel::Errors
  extend ActiveModel::Naming

  def initialize
    @errors = ActiveModel::Errors.new(self)
  end

  attr_accessor :name
  attr_reader   :errors

  def validate!
    errors.add(:name, :blank, message: "cannot be nil") if name.nil?
  end

  # The following methods are needed to be minimally implemented

  def read_attribute_for_validation(attr)
    send(attr)
  end

  def self.human_attribute_name(attr, options = {})
    attr
  end

  def self.lookup_ancestors
    [self]
  end
end

最后三个方法对于 Errors 能够正确生成错误消息并处理多种语言是必须实现的。当然,如果您扩展您的对象并包含 ActiveModel::Translation,则无需实现后两个。同样,使用 ActiveModel::Validations 将会为您处理与验证相关的方法。

以上允许您执行

person = Person.new
person.validate!            # => ["cannot be nil"]
person.errors.full_messages # => ["name cannot be nil"]
# etc..
方法
#
A
C
D
E
F
G
H
I
K
M
N
O
S
T
W
包含的模块

Attributes

[R] errors

实际的 Error 对象数组。此方法别名为 objects

[R] objects

实际的 Error 对象数组。此方法别名为 objects

类公共方法

new(base)

传入正在使用 errors 对象的实例。

class Person
  def initialize
    @errors = ActiveModel::Errors.new(self)
  end
end
# File activemodel/lib/active_model/errors.rb, line 114
def initialize(base)
  @base = base
  @errors = []
end

实例公共方法

[](attribute)

当传入一个符号或方法名时,返回该方法的错误数组。

person.errors[:name]  # => ["cannot be nil"]
person.errors['name'] # => ["cannot be nil"]
# File activemodel/lib/active_model/errors.rb, line 226
def [](attribute)
  messages_for(attribute)
end

add(attribute, type = :invalid, **options)

attribute 上添加一个 type 类型的新错误。同一个 attribute 可以添加多个错误。如果未提供 type,则默认为 :invalid

person.errors.add(:name)
# Adds <#ActiveModel::Error attribute=name, type=invalid>
person.errors.add(:name, :not_implemented, message: "must be implemented")
# Adds <#ActiveModel::Error attribute=name, type=not_implemented,
                            options={:message=>"must be implemented"}>

person.errors.messages
# => {:name=>["is invalid", "must be implemented"]}

如果 type 是一个字符串,它将被用作错误消息。

如果 type 是一个符号,它将使用适当的范围进行翻译(参见 generate_message)。

person.errors.add(:name, :blank)
person.errors.messages
# => {:name=>["can't be blank"]}

person.errors.add(:name, :too_long, count: 25)
person.errors.messages
# => ["is too long (maximum is 25 characters)"]

如果 type 是一个 proc,它将被调用,允许使用例如 Time.now 在错误中使用。

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

person.errors.add(:name, :invalid, strict: true)
# => ActiveModel::StrictValidationFailed: Name is invalid
person.errors.add(:name, :invalid, strict: NameIsInvalid)
# => NameIsInvalid: Name is invalid

person.errors.messages # => {}

如果错误不直接与单个属性关联,则 attribute 应设置为 :base

person.errors.add(:base, :name_or_email_blank,
  message: "either name or email must be present")
person.errors.messages
# => {:base=>["either name or email must be present"]}
person.errors.details
# => {:base=>[{error: :name_or_email_blank}]}
# File activemodel/lib/active_model/errors.rb, line 339
def add(attribute, type = :invalid, **options)
  attribute, type, options = normalize_arguments(attribute, type, **options)
  error = Error.new(@base, attribute, type, **options)

  if exception = options[:strict]
    exception = ActiveModel::StrictValidationFailed if exception == true
    raise exception, error.full_message
  end

  @errors.append(error)

  error
end

added?(attribute, type = :invalid, options = {})

如果错误与提供的 attributetype 匹配,则返回 true,否则返回 falsetype 的处理方式与 add 方法相同。

person.errors.add :name, :blank
person.errors.added? :name, :blank           # => true
person.errors.added? :name, "can't be blank" # => true

如果错误需要选项,则在提供正确选项时返回 true,在提供不正确或缺失选项时返回 false

person.errors.add :name, :too_long, count: 25
person.errors.added? :name, :too_long, count: 25                     # => true
person.errors.added? :name, "is too long (maximum is 25 characters)" # => true
person.errors.added? :name, :too_long, count: 24                     # => false
person.errors.added? :name, :too_long                                # => false
person.errors.added? :name, "is too long"                            # => false
# File activemodel/lib/active_model/errors.rb, line 369
def added?(attribute, type = :invalid, options = {})
  attribute, type, options = normalize_arguments(attribute, type, **options)

  if type.is_a? Symbol
    @errors.any? { |error|
      error.strict_match?(attribute, type, **options)
    }
  else
    messages_for(attribute).include?(type)
  end
end

as_json(options = nil)

返回一个可以作为此对象 JSON 表示形式的 Hash。您可以传递 :full_messages 选项。这决定了 JSON 对象是否应包含完整消息(默认为 false)。

person.errors.as_json                      # => {:name=>["cannot be nil"]}
person.errors.as_json(full_messages: true) # => {:name=>["name cannot be nil"]}
# File activemodel/lib/active_model/errors.rb, line 244
def as_json(options = nil)
  to_hash(options && options[:full_messages])
end

attribute_names()

返回所有错误属性名称

person.errors.messages        # => {:name=>["cannot be nil", "must be specified"]}
person.errors.attribute_names # => [:name]
# File activemodel/lib/active_model/errors.rb, line 234
def attribute_names
  @errors.map(&:attribute).uniq.freeze
end

clear

清除所有错误。但是,清除错误并不会使模型有效。下次运行验证时(例如,通过 ActiveRecord::Validations#valid?),如果任何验证失败,错误集合将再次填充。

# File activemodel/lib/active_model/errors.rb, line 77
    

delete(attribute, type = nil, **options)

删除 key 的消息。返回已删除的消息。

person.errors[:name]        # => ["cannot be nil"]
person.errors.delete(:name) # => ["cannot be nil"]
person.errors[:name]        # => []
# File activemodel/lib/active_model/errors.rb, line 212
def delete(attribute, type = nil, **options)
  attribute, type, options = normalize_arguments(attribute, type, **options)
  matches = where(attribute, type, **options)
  matches.each do |error|
    @errors.delete(error)
  end
  matches.map(&:message).presence
end

details()

返回一个包含属性及其错误详细信息数组的 Hash

# File activemodel/lib/active_model/errors.rb, line 273
def details
  hash = group_by_attribute.transform_values do |errors|
    errors.map(&:details)
  end
  hash.default = EMPTY_ARRAY
  hash.freeze
  hash
end

each(&block)

遍历每个错误对象。

person.errors.add(:name, :too_short, count: 2)
person.errors.each do |error|
  # Will yield <#ActiveModel::Error attribute=name, type=too_short,
                                    options={:count=>3}>
end
# File activemodel/lib/active_model/errors.rb, line 64
    

empty?

如果没有错误,则返回 true。

# File activemodel/lib/active_model/errors.rb, line 87
    

full_message(attribute, message)

为给定的属性返回一个完整的消息。

person.errors.full_message(:name, 'is invalid') # => "Name is invalid"
# File activemodel/lib/active_model/errors.rb, line 448
def full_message(attribute, message)
  Error.full_message(attribute, message, @base)
end

full_messages()

以数组形式返回所有完整的错误消息。

class Person
  validates_presence_of :name, :address, :email
  validates_length_of :name, in: 5..30
end

person = Person.create(address: '123 First St.')
person.errors.full_messages
# => ["Name is too short (minimum is 5 characters)", "Name can't be blank", "Email can't be blank"]
也别名为: to_a
# File activemodel/lib/active_model/errors.rb, line 412
def full_messages
  @errors.map(&:full_message)
end

full_messages_for(attribute)

以数组形式返回给定属性的所有完整错误消息。

class Person
  validates_presence_of :name, :email
  validates_length_of :name, in: 5..30
end

person = Person.create()
person.errors.full_messages_for(:name)
# => ["Name is too short (minimum is 5 characters)", "Name can't be blank"]
# File activemodel/lib/active_model/errors.rb, line 427
def full_messages_for(attribute)
  where(attribute).map(&:full_message).freeze
end

generate_message(attribute, type = :invalid, options = {})

在默认范围(activemodel.errors.messages)下翻译错误消息。

Error 消息首先在 activemodel.errors.models.MODEL.attributes.ATTRIBUTE.MESSAGE 中查找,如果不存在,则在 activemodel.errors.models.MODEL.MESSAGE 中查找,如果仍然不存在,则返回默认消息的翻译(例如 activemodel.errors.messages.MESSAGE)。翻译后的模型名称、翻译后的属性名称和值可用于插值。

在使用模型继承时,它会检查所有继承的模型,但前提是模型本身尚未找到。假设您有 class Admin < User; end,并且您想要 title 属性的 :blank 错误消息的翻译,它会查找以下翻译

  • activemodel.errors.models.admin.attributes.title.blank

  • activemodel.errors.models.admin.blank

  • activemodel.errors.models.user.attributes.title.blank

  • activemodel.errors.models.user.blank

  • 您通过 options 哈希在 activemodel.errors 范围中提供的任何默认值

  • activemodel.errors.messages.blank

  • errors.attributes.title.blank

  • errors.messages.blank

# File activemodel/lib/active_model/errors.rb, line 476
def generate_message(attribute, type = :invalid, options = {})
  Error.generate_message(attribute, type, @base, options)
end

group_by_attribute()

返回一个包含属性及其 Error 对象数组的 Hash

person.errors.group_by_attribute
# => {:name=>[<#ActiveModel::Error>, <#ActiveModel::Error>]}
# File activemodel/lib/active_model/errors.rb, line 286
def group_by_attribute
  @errors.group_by(&:attribute)
end

has_key?(attribute)

别名: include?

import(error, override_options = {})

导入一个错误。导入的错误将被包装为 NestedError,提供对原始错误对象的访问。如果需要覆盖属性或类型,请使用 override_options

Options

  • :attribute - 覆盖错误所属的属性。

  • :type - 覆盖错误的类型。

# File activemodel/lib/active_model/errors.rb, line 151
def import(error, override_options = {})
  [:attribute, :type].each do |key|
    if override_options.key?(key)
      override_options[key] = override_options[key].to_sym
    end
  end
  @errors.append(NestedError.new(@base, error, override_options))
end

include?(attribute)

如果错误消息包含给定键 attribute 的错误,则返回 true,否则返回 false

person.errors.messages        # => {:name=>["cannot be nil"]}
person.errors.include?(:name) # => true
person.errors.include?(:age)  # => false
也别名为: has_key?, key?
# File activemodel/lib/active_model/errors.rb, line 199
def include?(attribute)
  @errors.any? { |error|
    error.match?(attribute.to_sym)
  }
end

key?(attribute)

别名: include?

merge!(other)

合并 other 中的错误,每个 Error 都包装为 NestedError

Parameters

Examples

person.errors.merge!(other)
# File activemodel/lib/active_model/errors.rb, line 171
def merge!(other)
  return errors if equal?(other)

  other.errors.each { |error|
    import(error)
  }
end

messages()

返回一个包含属性及其错误消息数组的 Hash

# File activemodel/lib/active_model/errors.rb, line 265
def messages
  hash = to_hash
  hash.default = EMPTY_ARRAY
  hash.freeze
  hash
end

messages_for(attribute)

以数组形式返回给定属性的所有错误消息。

class Person
  validates_presence_of :name, :email
  validates_length_of :name, in: 5..30
end

person = Person.create()
person.errors.messages_for(:name)
# => ["is too short (minimum is 5 characters)", "can't be blank"]
# File activemodel/lib/active_model/errors.rb, line 441
def messages_for(attribute)
  where(attribute).map(&:message)
end

of_kind?(attribute, type = :invalid)

如果属性上存在给定类型的错误,则返回 true,否则返回 falsetype 的处理方式与 add 方法相同。

person.errors.add :age
person.errors.add :name, :too_long, count: 25
person.errors.of_kind? :age                                            # => true
person.errors.of_kind? :name                                           # => false
person.errors.of_kind? :name, :too_long                                # => true
person.errors.of_kind? :name, "is too long (maximum is 25 characters)" # => true
person.errors.of_kind? :name, :not_too_long                            # => false
person.errors.of_kind? :name, "is too long"                            # => false
# File activemodel/lib/active_model/errors.rb, line 392
def of_kind?(attribute, type = :invalid)
  attribute, type = normalize_arguments(attribute, type)

  if type.is_a? Symbol
    !where(attribute, type).empty?
  else
    messages_for(attribute).include?(type)
  end
end

size

返回错误数量。

# File activemodel/lib/active_model/errors.rb, line 100
delegate :each, :clear, :empty?, :size, :uniq!, to: :@errors

to_a()

别名: full_messages

to_hash(full_messages = false)

返回一个包含属性及其错误消息的 Hash。如果 full_messagestrue,则包含完整消息(参见 full_message)。

person.errors.to_hash       # => {:name=>["cannot be nil"]}
person.errors.to_hash(true) # => {:name=>["name cannot be nil"]}
# File activemodel/lib/active_model/errors.rb, line 253
def to_hash(full_messages = false)
  message_method = full_messages ? :full_message : :message
  group_by_attribute.transform_values do |errors|
    errors.map(&message_method)
  end
end

where(attribute, type = nil, **options)

搜索匹配 attributetypeoptions 的错误。

只有提供的参数才会被匹配。

person.errors.where(:name) # => all name errors.
person.errors.where(:name, :too_short) # => all name errors being too short
person.errors.where(:name, :too_short, minimum: 2) # => all name errors being too short and minimum is 2
# File activemodel/lib/active_model/errors.rb, line 186
def where(attribute, type = nil, **options)
  attribute, type, options = normalize_arguments(attribute, type, **options)
  @errors.select { |error|
    error.match?(attribute, type, **options)
  }
end