跳至內容 跳至搜尋
方法
V

執行個體公開方法

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_validation,或 if: Proc.new { |user| user.signup_step > 2 })。方法、程序或字串應傳回或評估為 truefalse 值。

  • :unless - 指定要呼叫的方法、程序或字串,以判斷驗證是否不應發生(例如 unless: :skip_validation,或 unless: Proc.new { |user| user.signup_step <= 2 })。方法、程序或字串應傳回或評估為 truefalse 值。

# 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 以取得更多資訊。

別名為:validates_size_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 屬性,且不能為空白或標記為要銷毀。

此驗證器委託 Active Model 進行存在驗證,並加入檢查以查看關聯物件是否標記為要銷毀。這可防止父物件成功驗證並儲存,然後刪除關聯物件,進而使父物件進入無效狀態。

請參閱 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_length_of

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 })。方法、程序或字串應傳回或評估為 truefalse 值。

  • :unless - 指定要呼叫的方法、程序或字串,以判斷驗證是否不應發生(例如 unless: :skip_validation,或 unless: 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 286
def validates_uniqueness_of(*attr_names)
  validates_with UniquenessValidator, _merge_attributes(attr_names)
end