- V
執行個體 public 方法
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 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_numericality_of(*attr_names) 連結
透過尝试使用 Kernel.Float
将其转换为浮点数(如果 only_integer
为 false
),或将其应用于正则表达式 /\A[+\-]?\d+\z/
(如果 only_integer
设置为 true
),来验证指定属性的值是否为数字。Kernel.Float
精度默认为列的精度值或 15。
更多信息,请参阅 ActiveModel::Validations::HelperMethods.validates_numericality_of
。
validates_presence_of(*attr_names) 連結
验证指定的属性是否不为空白(按照 Object#blank?
定义)。如果是关联属性,如果将关联对象标记为销毁,也会将关联对象视为空白。
class Person < ActiveRecord::Base
has_one :face
validates_presence_of :face
end
face 属性必须在对象中,且它不能空白或标记为要销毁。
此验证器让步于活动模型存在性验证,并检查关联对象未标记为销毁。这样可防止父对象成功验证并保存,然后删除关联对象,使父对象进入无效状态。
更多信息,请参阅 ActiveModel::Validations::HelperMethods.validates_presence_of
。
注意:如果关联属性已赋值但无效,则在此关联属性上使用此验证不会失败。如果要确保关联属性同时存在且有效,则还需要使用 validates_associated。
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
若要根據紀錄的狀態建立條件,請定義可使用參數呼叫的條件。此參數即代表紀錄本身。此範例會驗證標題在出版年度的唯一性。
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 291 def validates_uniqueness_of(*attr_names) validates_with UniquenessValidator, _merge_attributes(attr_names) end