跳至内容 跳至搜索
方法
V

实例公共方法

validates_absence_of(*attr_names)

验证指定属性是否不存在(由 Object#present? 定义)。如果属性是关联,则关联对象如果标记为销毁,也被认为不存在。

有关更多信息,请参见 ActiveModel::Validations::HelperMethods.validates_absence_of

# File activerecord/lib/active_record/validations/absence.rb, line 20
def validates_absence_of(*attr_names)
  validates_with AbsenceValidator, _merge_attributes(attr_names)
end

validates_associated(*attr_names)

验证关联对象是否都有效。适用于任何类型的关联。

class Book < ActiveRecord::Base
  has_many :pages
  belongs_to :library

  validates_associated :pages, :library
end

警告:此验证不能在关联的两端使用。这样做会导致循环依赖并导致无限递归。

注意:如果未分配关联,此验证不会失败。如果您想确保关联同时存在且保证有效,则还需要使用 validates_presence_of

配置选项

  • :message - 自定义错误消息(默认值为:“无效”)。

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

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

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

# File activerecord/lib/active_record/validations/associated.rb, line 60
def validates_associated(*attr_names)
  validates_with AssociatedValidator, _merge_attributes(attr_names)
end

validates_length_of(*attr_names)

验证指定属性是否符合提供的长度限制。如果属性是关联,则标记为销毁的记录不会被计算。

有关更多信息,请参见 ActiveModel::Validations::HelperMethods.validates_length_of

也被称为:validates_size_of
# File activerecord/lib/active_record/validations/length.rb, line 19
def validates_length_of(*attr_names)
  validates_with LengthValidator, _merge_attributes(attr_names)
end

validates_numericality_of(*attr_names)

通过尝试使用 Kernel.Float 将其转换为浮点数(如果 only_integerfalse)或将其应用于正则表达式 /\A[+\-]?\d+\z/(如果 only_integer 设置为 true),验证指定属性的值是否为数字。Kernel.Float 精度默认为列的精度值或 15。

有关更多信息,请参见 ActiveModel::Validations::HelperMethods.validates_numericality_of

# File activerecord/lib/active_record/validations/numericality.rb, line 31
def validates_numericality_of(*attr_names)
  validates_with NumericalityValidator, _merge_attributes(attr_names)
end

validates_presence_of(*attr_names)

验证指定属性是否不为空(由 Object#blank? 定义)。如果属性是关联,则关联对象如果标记为销毁,也被认为为空。

class Person < ActiveRecord::Base
  has_one :face
  validates_presence_of :face
end

面部属性必须存在于对象中,并且不能为空或标记为销毁。

此验证器委托给 Active Model 的存在验证,并添加检查以查看关联对象是否未标记为销毁。这可以防止父对象成功验证并保存,这将删除关联对象,从而使父对象处于无效状态。

有关更多信息,请参见 ActiveModel::Validations::HelperMethods.validates_presence_of

注意:如果使用关联并分配了关联但无效,此验证在使用关联时不会失败。如果您想确保关联同时存在且有效,则还需要使用 validates_associated

# File activerecord/lib/active_record/validations/presence.rb, line 40
def validates_presence_of(*attr_names)
  validates_with PresenceValidator, _merge_attributes(attr_names)
end

validates_size_of(*attr_names)

validates_uniqueness_of(*attr_names)

验证指定属性的值在整个系统中是否唯一。这对于确保只有一个用户可以命名为“davidhh”很有用。

class Person < ActiveRecord::Base
  validates_uniqueness_of :user_name
end

它还可以验证指定属性的值是否基于 :scope 参数唯一

class Person < ActiveRecord::Base
  validates_uniqueness_of :user_name, scope: :account_id
end

甚至多个范围参数。例如,确保教师只能在特定学期的课程中安排一次课。

class TeacherSchedule < ActiveRecord::Base
  validates_uniqueness_of :teacher_id, scope: [:semester_id, :class_id]
end

还可以将唯一性约束限制在与某些条件匹配的记录集上。在本例中,验证标题属性的唯一性时,不会考虑已归档的文章

class Article < ActiveRecord::Base
  validates_uniqueness_of :title, conditions: -> { where.not(status: 'archived') }
end

要根据记录的状态构建条件,请定义一个参数可调用的条件,该参数将是记录本身。本例验证标题在出版年份中是唯一的

class Article < ActiveRecord::Base
  validates_uniqueness_of :title, conditions: ->(article) {
    published_at = article.published_at
    where(published_at: published_at.beginning_of_year..published_at.end_of_year)
  }
end

创建记录时,会执行检查以确保数据库中不存在具有指定属性(映射到列)的给定值的记录。更新记录时,会进行相同的检查,但会忽略记录本身。

配置选项

  • :message - 指定自定义错误消息(默认值为:“已被占用”)。

  • :scope - 一个或多个用于限制唯一性约束范围的列。

  • :conditions - 指定要包含的条件作为 WHERE SQL 片段,以限制唯一性约束查找(例如 conditions: -> { where(status: 'active') })。

  • :case_sensitive - 查找完全匹配。非文本列忽略。默认行为尊重默认数据库排序规则。

  • :allow_nil - 如果设置为 true,则如果属性为 nil,则跳过此验证(默认值为 false)。

  • :allow_blank - 如果设置为 true,则如果属性为空,则跳过此验证(默认值为 false)。

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

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

并发性和完整性

将此验证方法与 ActiveRecord::Base#save 结合使用不能保证不会出现重复记录插入,因为应用程序级别的唯一性检查本质上容易出现竞争条件。例如,假设两个用户试图同时发布评论,而评论的标题必须是唯一的。在数据库级别,这些用户执行的操作可以以以下方式交织

             User 1                 |               User 2
------------------------------------+--------------------------------------
# User 1 checks whether there's     |
# already a comment with the title  |
# 'My Post'. This is not the case.  |
SELECT * FROM comments              |
WHERE title = 'My Post'             |
                                    |
                                    | # User 2 does the same thing and also
                                    | # infers that their title is unique.
                                    | SELECT * FROM comments
                                    | WHERE title = 'My Post'
                                    |
# User 1 inserts their comment.     |
INSERT INTO comments                |
(title, content) VALUES             |
('My Post', 'hi!')                  |
                                    |
                                    | # User 2 does the same thing.
                                    | INSERT INTO comments
                                    | (title, content) VALUES
                                    | ('My Post', 'hello!')
                                    |
                                    | # ^^^^^^
                                    | # Boom! We now have a duplicate
                                    | # title!

解决此问题的最佳方法是在数据库表中使用 connection.add_index 添加唯一索引。在罕见的竞争条件发生的情况下,数据库将保证该字段的唯一性。

当数据库捕获到此类重复插入时,ActiveRecord::Base#save 将引发 ActiveRecord::StatementInvalid 异常。您可以选择让此错误传播(这将导致显示默认的 Rails 异常页面),或者您可以捕获它并重新启动事务(例如,通过告诉用户标题已存在,并要求他们重新输入标题)。此技术也称为 乐观并发控制

捆绑的 ActiveRecord::ConnectionAdapters 区分唯一索引约束错误和其他类型的数据库错误,方法是抛出 ActiveRecord::RecordNotUnique 异常。对于其他适配器,您必须解析(特定于数据库的)异常消息以检测这种情况。

以下捆绑的适配器抛出 ActiveRecord::RecordNotUnique 异常

# File activerecord/lib/active_record/validations/uniqueness.rb, line 291
def validates_uniqueness_of(*attr_names)
  validates_with UniquenessValidator, _merge_attributes(attr_names)
end