モデルの属性に自作のバリデーションを追加する
モデルの属性のバリデーションをしたいときに、バリデーションヘルパーの既存バリデーションだけでは足りないことがあると思います。
そのため、Rails ではバリデーションを自作することができます。
その一つの方法としてバリデーションメソッドがあります。
バリデーションメソッド
バリデーション用のメソッドを定義して、オブジェクトの保存時にそのメソッドによりバリデーションする方法です。
例えば、 name 属性を持つ Account モデルに対して、 name の prefix として hoge_
があるというバリデーションをしたい (?) 場合には、以下のようにします。
class Account < ActiveRecord::Base validate :prefix_hoge # 保存時に prefix_hoge によりバリデーションをする # バリデーションメソッド def prefix_hoge if name !~ /^hoge\_/ # バリデーションの条件 errors.add(:name, " は hoge_ から始まるようにしましょう!") # エラーメッセージ end end end
これにより、 prefix として hoge_
のない name を持つ Account のオブジェクトを保存しようとするとエラーになります。
# hoge_ あり irb(main):001:0> Account.first.update(name: 'hoge_test') Account Load (0.3ms) SELECT `accounts`.* FROM `accounts` ORDER BY `accounts`.`id` ASC LIMIT 1 (0.2ms) BEGIN SQL (0.3ms) UPDATE `accounts` SET `name` = 'hoge_test', `updated_at` = '2016-05-13 14:59:13' WHERE `accounts`.`id` = 1 (0.6ms) COMMIT => true # hoge_ なし irb(main):002:0> Account.first.update(name: 'test') Account Load (0.3ms) SELECT `accounts`.* FROM `accounts` ORDER BY `accounts`.`id` ASC LIMIT 1 (0.1ms) BEGIN (0.2ms) ROLLBACK => false
ですが、 複数の属性に対してバリデーションヘルパーとバリデーションメソッドの両方を利用すると、以下のように同一の属性のバリデーションの記述が分散してしまうことがあります。
class Account < ActiveRecord::Base validates :name, presence: true, length: { maximum: 10 } validates :email, presence: true validate :prefix_hoge validate :email_validation
バリデーションを自作する他の方法として、カスタムバリデータがあります。 こちらを使えば上記の点を防ぐことができます。
カスタムバリデータ
先ほどと同様のバリデーションを追加します。
カスタムバリデータは、 バリデーションを自作するためのクラスを継承したクラスを作ります。
クラスには ActiveModel::Validator と ActiveModel::EachValidator の二種類があるのですが、後者の方が使いやすいと思うのでそちらについてのみ書きます。
クラスをパスの通っている場所に作成します。
# lib/validators/prefix_hoge_validator.rb class PrefixHogeValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) # バリデーションメソッド if value !~ /^hoge\_/ record.errors.add(attribute, " は hoge_ から始まるようにしましょう!") end end end
バリデーションメソッドは必ず validate_each
とします。
validate_each
の引数の record
に保存対象のオブジェクトが、 attribute
にバリデーション対象の属性が、 value
に保存する値
が渡ってきます。
これを Account モデルで利用する際には、バリデーションヘルパーのように記述することができます。
class Account < ActiveRecord::Base validates :name, prefix_hoge: true
これで先ほどと同様のバリデーションをすることができます。
カスタムバリデータであれば、複数の属性に対してバリデーションヘルパーとバリデーションメソッドの両方を利用したとしても、以下のように対象の属性の記述が一箇所にまとまり見やすくなります。
class Account < ActiveRecord::Base validates :name, presence: true, length: { maximum: 10 }, prefix_hoge: true validates :email, presence: true email_validation: true
とはいえ、毎回カスタムバリデータを使うのではなく、それぞれのメリットデメリットを見極めて使うと良さそうです。