- 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
- 指定一个方法、过程或字符串来调用以确定是否应执行验证(例如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
值。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/validations/associated.rb, line 54 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
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
还可以将唯一性约束限制为一组匹配特定条件的记录。在此示例中,在验证标题属性的唯一性时,不会考虑已归档的文章
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
- 指定一个方法、过程或字符串来调用以确定是否应执行验证(例如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
值。
并发性和完整性
将此验证方法与 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 286 def validates_uniqueness_of(*attr_names) validates_with UniquenessValidator, _merge_attributes(attr_names) end