Rails Validationについて
データ管理はしっかりやりたい
DBにデータが保存される時に、そのデータが正しいかどうかを検証する仕組みをバリデーションという。
バリデーションのトリガー
バリデーションが走るメソッド群
- create
- create!
- save
- save!
- update
- update!
上記のメソッドはオプションでバリデーションをスキップすることも可能
save(validate: false)
バリデーションがスキップされるメソッド群
- decrement!
- decrement_counter
- increment!
- increment_counter
- toggle!
- touch
- update_all
- update_attribute
- update_column
- update_columns
- update_counters
Validate
通常のバリデーションです。 modelに定義して利用します。
class Recipe < ActiveRecord::Base # これでtitleがnullだとデータのInsertが行われず、弾かれます validates :title, presence: true end
valid?
とinvalid?
が用意されておりboolean型の値が返ってきます。
Recipe.new(title: "レシピタイトル").valid? #=> true Recipe.new(title: null).valid? #=> false Recipe.new(title: "レシピタイトル").invalid? #=> false Recipe.new(title: null).invalid? #=> true
カスタムValidate
単体のmodelで独自のvalidationを定義し、使いたい場合に利用する。
validate link_url_cannot_be_load def link_url_cannot_be_load if @obj.url.include?(BASIC_DOMAIN) errors[:link_url] << "でURLは利用することができません。可能ドメインか確認してください" end end
カスタムValidator
複数のmodelで独自のvalidationを定義し、使いまわしたい場合に利用する。
もしくは単体のmodelでも複数の独自validationを定義し使いたい場合に利用する。
開発者にもよるが、自分は上記の理由と定義を決めている。ここは個人の好みにもよるのかもしれない・・・
そしてRailsのapp/以下にvalidators
ディレクトリを作ってその中にカスタムvalidatorをまとめておく
カスタムバリデータはActiveModel::Validatorを拡張したクラス。
クラスにはvalidateメソッド
が実装されている必要がある。
class Recipe << ActiveRecord::Base include ActiveModel::Validations validates_with ContentValidator end class ContentValidator < ActiveModel::Validator # 必ずvalidateメソッドを実装する # 引数にはレコードを1つ取り、それに対してのバリデーションを実行する def validate(record) if record.description.blank? record.errors[:description] << "が空です" end end end
- Validates
- カスタムValidate
- カスタムValidator
3つのバリデーションを使いこない堅牢なシステムを構築していきたい。
データまわりの定義は厳密に決めていくことが大切だと自分は考えています。
理由としては一度データが入ったデータベースは変更が難しくなってしまうからです。
アプリケーションレイヤーのvalidation制御はもちろん。
DB側での外部キー制約、ユニークキー制約、複数の一意制約、null制約などルールをしっかり決めておくことが大切。
新規開発においては、使用がコロコロ変わるのはしょっちゅうあるのである程度変更があることを前提に開発していくと良い。
ただ、リリース段階まで行く時にはきっちりと制約周りは定義することが守るべきルールとしてある。