ActiveRecordクラスに動的にバリデーションコードを追加する
RailsWay 250ページあたりに出てくる話題として、ActiveRecordでレコードを読み出す時に動的にバリデーションコードを定義するという話題があり、場合によっては非常に便利だが、RailsWayのコードそのままだとちょっとアレでうまくいかないので、正しいコードに修正してみた。
もともとは、こんな感じ:
class Account < ActiveRecord::Base ... private def after_find singleton = class << self; self; end singleton.class_eval(config) end end
これで基本は問題ないのだが、configの部分に投入するバリデーションコードは
validates_numericality_of :product_code, :only_integer => true validates_length_of :product_code, :is => 10
ではなく、
ActiveRecord::Base.validates_numericality_of :product_code, :only_integer => true ActiveRecord::Base.validates_length_of :product_code, :is => 10
のようにActiveRecord::Baseを指定してあげないとエラーが出る事もなくバリデーションが正しく実行されないという現象になる。
この例ではafter_findコールバックを使っているけど、before_validationなどで使うほうが一般的かもしれない。
ちなみになんらかの工夫をしないと多重にバリデーションを追加してしまう事態になるので要注意。