猶豫到最後一小時,真想不到其他主題
最後決定來寫資料驗證(validation)
之所以不想寫這個主題,是因為我在這邊沒什麼特別的心得
寫起來就會很像教科書抄錄
跟文件或API指引沒有太大的不同
頂多只是用我自己的邏輯消化一遍
無論如何,循著model裡的元素一個一個介紹
這樣的模式令人很放心,就決定依序進行下去
我這幾天陸續談了「淺談scope -- 常用的條件通通藏在裡面」
與「淺談delegate -- 探囊取物」
加上今天這篇,好像默默自成一種風格
資料驗證是網站很重要的一部分
做得不好不只可能造成錯誤,更嚴重可能有資安上的隱憂
如果由使用者到資料庫、由前往後看
其實有很多階段都可以做驗證
有一個觀念很重要:
「讓錯誤的資料越早被擋下來越好」
也就是能在前端擋就不要在後端擋;
能在後端擋就不要用資料庫擋。
不過rails很貼心的做了前後端整合
只要有做驗證,前端會自動幫忙擋下
最基本的驗證如下:
class User < ActiveRecord::Base
validates_presence_of :name
end
很明顯是在User.name判斷不可為空
這樣在前端新增或編輯時,就會自動檢查並且擋下
也可以使用這種寫法,似乎是新的建議寫法:
class User < ActiveRecord::Base
validates :name, presence: true
end
如果要同時驗證多個欄位,只需要逗號分隔
除了是否為空之外,也可以驗證許多不同的資料細節,例如
class User < ActiveRecord::Base
validates :name, :email, presence: true
#同時驗證多個欄位
validates :price, presence: true, numericality: { only_integer: true }
#只能是數字
validates :age, length: {minimum: 5, maximum: 100}
#長度最大100,最小5
validates :age, length: { in: 5..100 }
#或是這樣寫
validates :email, uniqueness: true
#必須唯一,當然這也可以在資料庫階段就防止
end
還有很多很多,這邊就不列舉
如果原生的方法都不滿意,也可以寫自己客製化的validate
我這邊直接提供官方的範例如下:(因為我沒有自己實作過XD)
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
只想在特定的動作才驗證,不想要隨時驗證,也可以
validates :email, uniqueness: true, on: :create
#只有在create的時候才驗證唯一
或是條件相當複雜,可以獨立為一個方法
class Order < ApplicationRecord
validates :card_number, presence: true, if: :paid_with_card?
#只有當訂單為信用卡時,信用卡號碼才不可為空
def paid_with_card?
payment_type == "card"
end
end
設置上相當靈活
但是凡事總有例外,如果千辛萬苦設定了一堆驗證
假如有資料要偷跑,略過驗證怎麼辦?
別擔心,只要如下:
event.save( validate: false )
剛剛的條件都可以不算數啦!!
是不是很方便呢?
資料驗證相當重要,而且要記得處理好驗證不過的處理唷
像我就吃過相當多資料驗證不過導致沒存進資料庫
但是程式照樣執行的悶虧,不可不慎呢