略過內容 略過搜尋
方法
V

執行個體 public 方法

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 - 指定要呼叫的方法、程序或字串,以判斷是否應執行驗證(例如:if: :allow_validationif: Proc.new { |user| user.signup_step > 2 })。方法、程序或字串應傳回或計算為 truefalse 值。

  • :unless - 指定要呼叫的方法、程序或字串,以判斷是否不應執行驗證(例如:unless: :skip_validationunless: Proc.new { |user| user.signup_step <= 2 })。方法、程序或字串應傳回或計算為 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

# 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

face 属性必须在对象中,且它不能空白或标记为要销毁。

此验证器让步于活动模型存在性验证,并检查关联对象未标记为销毁。这样可防止父对象成功验证并保存,然后删除关联对象,使父对象进入无效状态。

更多信息,请参阅 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

还可以将唯一性约束限制在符合特定条件的一组记录上。在此示例中,在验证 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_validationif: Proc.new { |user| user.signup_step > 2 })。方法、程序或字串應傳回或計算為 truefalse 值。

  • :unless - 指定要呼叫的方法、程序或字串,以判斷是否不應執行驗證(例如:unless: :skip_validationunless: Proc.new { |user| user.signup_step <= 2 })。方法、程序或字串應傳回或計算為 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