validates_presence_of は何をしているのか?
ActiveRecord 1.15.3の話です。
いきなりですがソースを追ってみます。
/usr/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/validations.rb
1| def validates_presence_of(*attr_names) 2| configuration = { :message => ActiveRecord::Errors.default_error_messages[:blank], :on => :save } 3| configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash) 4| 5| # can't use validates_each here, because it cannot cope with nonexistent attributes, 6| # while errors.add_on_empty can 7| attr_names.each do |attr_name| 8| send(validation_method(configuration[:on])) do |record| 9| unless configuration[:if] and not evaluate_condition(configuration[:if], record) 10| record.errors.add_on_blank(attr_name,configuration[:message]) 11| end 12| end 13| end 14| end
2行目でオプションの初期設定している。まぁこれはこれでいいでしょう。
3行目で validates_presence_of の引数の最後がHashだったら2行目で設定したオプションの値を上書きしている。
5,6行目のコメントは
validates_eachだと存在しないアトリビュートを上手く扱えないのでerros.add_on_emptyが使えている間はここでvalidates_eachを使いません。
って書いてあるのかな?
で、7行目からが本番。
3行目でオプションのHashはpopされてattr_namesからはなくなっているので、attr_namesは純粋にvalidates_presence_ofの対象となるアトリビュート名のみになっている。
で、これをeachで回す。
回して何をするかというと validation_method(configuration[:on]) の戻り値を send している。
/usr/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/validations.rb
def validation_method(on) case on when :save then :validate when :create then :validate_on_create when :update then :validate_on_update end end
validates_presence_of の :on に従って validate, validate_on_create, validate_on_update のいづれかが send される事になりますね。
validate, validate_on_create, validate_on_updateは
/usr/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/validations.rb
def validate(*methods, &block) methods << block if block_given? write_inheritable_set(:validate, methods) end def validate_on_create(*methods, &block) methods << block if block_given? write_inheritable_set(:validate_on_create, methods) end def validate_on_update(*methods, &block) methods << block if block_given? write_inheritable_set(:validate_on_update, methods) end
と、いった感じなので :if の条件に合致した時に record.errors.add_on_blank(attr_name,configuration[:message]) が発動する感じです。
/usr/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/validations.rb
def add_on_blank(attributes, msg = @@default_error_messages[:blank]) for attr in [attributes].flatten value = @base.respond_to?(attr.to_s) ? @base.send(attr.to_s) : @base[attr.to_s] add(attr, msg) if value.blank? end end
add_on_blankはこうなっているので渡された@base.attr_nameがあるかどうかチェックして、あるようであれば@base.sttr_nameの戻り値、なければ@base[attr_name]の戻り値を取得して、それに対してblank?でチェック。trueであればエラーを追加している感じですね。
このチェックに blank? を使っているので boolean を取るアトリビュートに対して validates_presence_of を使うと false.blank? # => ture なので vaidates_presence_of が使えない所以ですね。