Active Record Validations part 2

Posted by Anthony Chao on 2019-09-30

我們繼續接續昨天 Active Record Validation 的內容

Length

length 是用來限制輸入資料的長度,選項有四種可以使用
minimummaximum 是用來限制最少跟最多的字數, in 是用來限制字數範圍,is則是限制只能這個數量的字數

1
2
3
4
5
6
class Person < ApplicationRecord
validates :name, length: { minimum: 2 }
validates :bio, length: { maximum: 500 }
validates :password, length: { in: 6..20 }
validates :registration_number, length: { is: 6 }
end

Numericality

numericality 使用的範圍很大,凡是跟數字有關的幾乎都是用這個驗證,最基本的就是限制輸入值必須為數字,另外還可以使用 only_integer: true 限制只能是整數

1
2
3
class Player < ApplicationRecord
validates :games_played, numericality: { only_integer: true }
end

除此之外,還有一連串屬性來限制數字範圍,比方說 :greater_than_or_equal_to:odd 等等,其他還有很多,有需要的可以去翻翻 Rails Guide 喔~

Presence

這個驗證是最常用的,presence: true 用來檢查此欄位是否為空值,這裏的空值是 nil 或者空字串都會被抓出來

1
2
3
4
class LineItem < ApplicationRecord
belongs_to :order
validates :order, presence: true
end

如果在關聯性之間更謹慎一點,我們可以在 belongs_to 的那個欄位後面,再寫一次 presence: true,如此一來不只檢查 foreign_key 是不是空值,還會檢查這筆資料是否真的存在

Absence

就是 presence 的反義,目前還沒用到過…

Uniqueness

用來驗證是否在此欄位中為唯一值

1
2
3
class Account < ApplicationRecord
validates :email, uniqueness: true
end

另外還有兩個選項可以用: scope / case_sensitive
其中 scope 較值得一提,他用來驗證多重欄位組合是否唯一,比方說

1
2
3
class Holiday < ApplicationRecord
validates :name, uniqueness: { scope: :year}
end

這個例子代表名字重複沒關係,但至少你的 year 欄位不能是一樣的年份,反之亦然

Validates_with

validates_with 後面接的是類別或者多個類別,這通常用在比較複雜的驗證需要自訂成 class

1
2
3
4
5
6
7
8
9
10
11
class GoodnessValidator < ActiveModel::Validator
def validate(record)
if record.first_name == "Evil"
record.errors[:base] << "This person is evil"
end
end
end

class Person < ApplicationRecord
validates_with GoodnessValidator
end

如果再更複雜一些,需要做出實體,那你可能會想做出 PORO (plain old Ruby object) 來輔助

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

class Person < ApplicationRecord
validate do |person|
GoodnessValidator.new(person).validate
end
end

class GoodnessValidator
def initialize(person)
@person = person
end

def validate
if some_complex_condition_involving_ivars_and_private_methods?
@person.errors[:base] << "This person is evil"
end
end

# ...
end

Validates_each

validates_each 後面接的是 block

1
2
3
4
5
6

class Person < ApplicationRecord
validates_each :name, :surname do |record, attr, value|
record.errors.add(attr, 'must start with upper case') if value =~ /\A[[:lower:]]/
end
end

我們在驗證這部分的內容就介紹到這裡~ Rails Guide 在這之後的內容都是一些延伸用法跟組合技,大家有用到的時候再去看看囉!

參考資料:

Rails Guide





prevent_hack