- 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
- 自定义错误消息(默认值为:“无效”)。 -
: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) 链接
通过尝试使用 Kernel.Float
将其转换为浮点数(如果 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
面部属性必须存在于对象中,并且不能为空或标记为销毁。
此验证器委托给 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
还可以将唯一性约束限制在与某些条件匹配的记录集上。在本例中,验证标题属性的唯一性时,不会考虑已归档的文章
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 或字符串应返回或评估为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