Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I combine multiple Rails validations for the same :if condition?

I have a model with many validations that can be grouped based on various conditions. The brute force way to handle it would be:

validates_presence_of :attr1, :if => :condition1
validates_something :attr2, :if => :condition1
validates_something_else :attr3, :if => :condition1
...

validates_presence_of :attr4, :if => :condition2
validates_something :attr5, :if => :condition2
validates_presence_of :attr6, :if => :condition2
...

But that doesn't seem very DRY. Is there a good way to group the validations based on the conditions? The approach I came up with is:

class Condition1Validator < ActiveModel::Validator
  def validate(record)
    record.instance_eval do
      validates_presence_of :attr1
      validates_something, :attr2
      validates_something_else :attr3
    end
  end
end
validates_with Condition1Validator, :if => :condition1

class Condition2Validator < ActiveModel::Validator
...
end
validates_with Condition2Validator, :if => :condition2

Can anyone think of a better way?

Update: the way I posted above is flawed in that you cannot have if, unless, etc on the nested validators. Jesse's solution is much better.

like image 241
Brian Deterling Avatar asked Apr 07 '11 16:04

Brian Deterling


1 Answers

This approach is from the multi-step wizard, where you only want to validate if you are on that wizard step. Should work for you as well

class YourModel 

  with_options :if => lambda { |o| o.whatever == "whatever" } do |on_condition|
    on_condition.validates_presence_of :address
    on_condition.validates_presence_of :city
  end

  with_options :if => lambda { |o| o.condition_the_second == "whatever" } do |on_condition|
    on_condition.validates_presence_of :foo
    on_condition.validates_presence_of :bar
  end
end
like image 178
Jesse Wolgamott Avatar answered Sep 28 '22 00:09

Jesse Wolgamott