結論
何れもvalidateの呼び出しに還元され、set_callbackで登録される。
準備
app/models/user.rb
class User < ActiveRecord::Base
validates :name, my: {hoge: :fuga}, if: :name_present?
private
def name_present?
true
end
end
app/validators/my_validator.rb
class MyValidator < ActiveModel::Validator
def initialize(options)
Rails.logger.debug 'in MyValidator#options'
Rails.logger.debug options
end
def validate(user)
end
private
end
呼び出し関係
/active_model/validations/validates.rb
module ActiveModel
module Validations
module ClassMethods
...
def validates(*attributes)
...
# validates_withが次の形で呼ばれる
# シンボル :my から MyValidator クラスへ変換される事に注意
#
# validates_with(
# MyValidator,
# {:if=>:name_present?, :attributes=>[:name], :hoge=>:fuga}
# )
active_model/validations/with.rb
module ActiveModel
module Validations
module ClassMethods
...
def validates_with(*args, &block)
...
# validateが次の形で呼ばれる
#
# validate(
# #<MyValidator:0x007fb1535f2c40>,
# {:if=>:name_present?, :hoge=>:fuga, :class=>User}
# )
#
# MyValidatorはインスタンスで呼ばれる事に注意
# newの引数にオプションとブロックが渡される。バリデータのinitializeで利用できる
# klass.new(options, &block)
#
# アトリビュート指定はどこへ行った?
# メソッドの途中で _validators[attribute.to_sym] << validator
/active_model/validations.rb
module ActiveModel
module Validations
module ClassMethods
...
def validate(*args, &block)
...
# set_callbackが次の形で呼ばれる
#
# set_callback(
# [
# #<MyValidator:0x007fb1535f2c40>,
# {:if=>:name_present?, :attributes=>[:name], :hoge=>:fuga, :class=>User}
# ]
他
validates_xxx_of は 単にvalidates_withへのラッパー