LoginSignup
2
5

More than 5 years have passed since last update.

オレオレvalidate撲滅

Last updated at Posted at 2015-02-05

オレオレ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 を組むことが出来た気がします

2
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
5