- V
实例公共方法
validates_absence_of(*attr_names) 链接
验证指定属性不存在(根据 Object#present? 定义)。如果属性是关联,当关联对象被标记为销毁时,该关联对象也被视为不存在。
有关更多信息,请参阅 ActiveModel::Validations::HelperMethods.validates_absence_of。
来源: 显示 | 在 GitHub 上
# 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- 自定义错误消息(默认值:“is invalid”)。 -
: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值。
来源: 显示 | 在 GitHub 上
# 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。
来源: 显示 | 在 GitHub 上
# 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) 链接
通过尝试将指定属性的值转换为浮点数(如果 only_integer 为 false)或将其应用于正则表达式 /\A[+\-]?\d+\z/(如果 only_integer 设置为 true)来验证其是否为数字。Kernel.Float 的精度默认为列的精度值或 15。
有关更多信息,请参阅 ActiveModel::Validations::HelperMethods.validates_numericality_of。
来源: 显示 | 在 GitHub 上
# 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
face 属性必须存在于对象中,且不能为空或标记为销毁。
此验证器将依赖 Active Model 的存在性验证,并添加一个检查以确保关联对象未被标记为销毁。这可以防止父对象成功验证并保存,然后删除关联对象,从而使父对象处于无效状态。
有关更多信息,请参阅 ActiveModel::Validations::HelperMethods.validates_presence_of。
注意:在使用此验证与关联时,如果后者已被分配但无效,此验证不会失败。如果要确保其既存在又有效,您还需要使用 validates_associated。
来源: 显示 | 在 GitHub 上
# 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_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
还可以将唯一性约束限制在满足特定条件的记录集内。在此示例中,在验证 title 属性的唯一性时,不会考虑已存档的文章。
class Article < ActiveRecord::Base validates_uniqueness_of :title, conditions: -> { where.not(status: 'archived') } end
要根据记录的状态构建条件,请定义一个可以接收记录本身作为参数的可调用条件。此示例验证 title 在出版年份是否唯一。
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- 指定自定义错误消息(默认值:“has already been taken”)。 -
:scope- 一个或多个列,用于限制唯一性约束的作用域。 -
:conditions- 指定要包含的条件,作为WHERESQL 片段来限制唯一性查找(例如: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 或字符串应返回或计算为true或false值。 -
:unless- 指定一个方法、proc 或字符串,用于确定是否不应执行验证(例如:unless: :skip_validation,或unless: Proc.new { |user| user.signup_step <= 2 })。该方法、proc 或字符串应返回或计算为true或false值。
并发和完整性¶ ↑
将此验证方法与 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 异常:
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/validations/uniqueness.rb, line 291 def validates_uniqueness_of(*attr_names) validates_with UniquenessValidator, _merge_attributes(attr_names) end