オレオレvalidation
よくオレオレvalidate作ってました。
メソッド内で erros の追加をする validation 用のメソッドだけど
valid? では呼ばれることのないやつ。
app/models/coffee.rb
class CoffeeMaker < ActiveRecord::Base
validate :name, presence: true
def validate_drip
return true if drippable?
errors[:base] << "ドリップできません"
errors.empty?
end
def validate_wash
return true if washable?
errors[:base] << "洗えません"
errors.empty?
end
def validate_warm
# ... validate_methods
errors.empty?
end
end
validation 処理の仕方はこんな感じ
coffee_maker = CoffeeMaker.find(2)
coffee_maker.warm! if coffee_maker.validate_warm
coffee_maker = CoffeeMaker.find(3)
coffee_maker.wash! if coffee_maker.validate_wash
coffee_maker = CoffeeMaker.find(1)
if coffee_maker.validate_drip && ( !coffee_maker.warm_start_after_drip? || coffee_maker.validate_warm )
coffee_maker.drip!
coffee_maker.warm! if coffee_maker.warm_start_after_drip?
end
複雑になってくるとどの処理のときにどの validation がかかっているのか
わけがわからなくなってきたので
ちゃんと Rails 標準の validation_context でまとめてみることにしました。
結論
app/models/coffee.rb
class CoffeeMaker < ActiveRecord::Base
VALIDATE_METHODS_ON_DRIP = [
# method_name symbol
]
VALIDATE_METHODS_ON_WARM = [
# method_name symbol
]
VALIDATE_METHODS_ON_WASH = [
# method_name symbol
]
validate :name, presence: true
with_options on: :drip do |will_drip|
validate :validate_on_drip
end
with_options on: :warm do |will_warm|
validate :validate_on_warm
end
with_options on: :wash do |wash|
validate :validate_on_wash
end
private
def validate_on_drip
VALIDATE_METHODS_ON_DRIP.each{|method| __send__(method)}
validate_on_warm if warm_start_after_drip?
end
def validate_on_warm
VALIDATE_METHODS_ON_WARM.each{|method| __send__(method)}
end
def validate_on_wash
VALIDATE_METHODS_ON_WASH.each{|method| __send__(method)}
end
end
coffee_maker = CoffeeMaker.find(2)
coffee_maker.warm! if coffee_maker.valid?(:warm)
coffee_maker = CoffeeMaker.find(3)
coffee_maker.wash! if coffee_maker.valid?(:wash)
coffee_maker = CoffeeMaker.find(1)
if coffee_maker.valid?(:drip)
coffee_maker.drip!
coffee_maker.warm! if coffee_maker.warm_start_after_drip?
end
同じメソッドを複数のコンテキストで使いたいとき、
直接書いてしまうと一番最後以外のものは無効になってしまうようなので気をつける。
↓の場合、 :context_a
は無効になる
validate: :validate_drip, on: :context_a
validate: :validate_drip, on: :context_b
これで少しは秩序だった validation を組むことが出来た気がします