也可以寫方法來驗證 Model 的狀態,並在 Model 狀態無效的情況下將錯誤加入 errors 集合。必須使用 validate 這個類別方法來註冊。
1234567891011121314
classPicture<ActiveRecord::Basebelongs_to:uservalidate:picture_size,on::create#注意沒有加 's'private# 驗證圖片的大小defpicture_sizeifpicture.size>5.megabyteserrors.add(:picture,"should be less than 5MB")#errors[:picture] << "should be less than 5MB"endendend
#app/validators/photo_size_validator.rbclassPhotoSizeValidator<ActiveModel::Validatordefvalidaterecordunlessvalidated?recordrecord.errors[:file_size]<<'must be less than 1 MB'endendprivatedefvalidated?recordrecord.file.size<1.megabytesendend#models/photo.rbclassPhotoValidatorincludeActiveModel::Validationsvalidates_withPhotoSizeValidator#也可帶入其他參數#validates_with PhotoSizeValidator, fields: [:size]#預設會被放入 options Hash,options[:size]end
以上在應用程式生命週期內只會實體化一次,而不是每次驗證時就實體化一次。所以使用實體變數時要很小心。
如果驗證類別足夠複雜的話,需要用到實體變數,可以用純 Ruby 物件(Plain Old Ruby Object, PORO)
PORO範例
12345678910111213141516171819
classPerson<ActiveRecord::Basevalidatedo|person|GoodnessValidator.new(person).validateendendclassGoodnessValidatordefinitialize(person)@person=personenddefvalidateifsome_complex_condition_involving_ivars_and_private_methods?@person.errors[:base]<<"This person is evil"endend# ...end
classEmailValidator<ActiveModel::EachValidatordefvalidate_each(record,attribute,value)unlessvalue=~/\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/irecord.errors[attribute]<<(options[:message]||"is not an email")endendendclassPerson<ActiveRecord::Basevalidates:email,presence:true,email:trueend
classPerson<ActiveRecord::Basevalidates_each:name,:surnamedo|record,attr,value|record.errors.add(attr,'must start with upper case')ifvalue=~/\A[[:lower:]]/endend
這個區塊接受記錄、屬性名稱、屬性值。在區塊裡可以寫任何驗證行為。驗證失敗時應給 Model 新增錯誤訊息,才能把記錄標記成非法的。