Validate presence of field only if another field is blank - Rails

Ruby on-RailsRuby on-Rails-3

Ruby on-Rails Problem Overview


I have a form with a mobile/cell number and a home phone number.

I want to have only validate presence of mobile/cell number if the phone number has been left blank or vice versa.

My current validations for these fields are as follows.

validates_presence_of :mobile_number
validates_presence_of :home_phone

validates_length_of :home_phone, :minimum => 12, :maximum => 12
validates_length_of :mobile_number, :minimum => 10, :maximum => 10, :allow_blank => true

validates_format_of :home_phone, :with => /\A[0-9]{2}\s[0-9]{4}\s[0-9]{4}/, :message => "format should be 02 9999 9999"

I thought I could have something like the following but not sure how to do this exactly.

validates_presence_of :mobile_number, :unless => :home_phone.blank?

I'm using Rails 3.

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

You don't need a lambda. This will do:

validates_presence_of :mobile_number, :unless => :home_phone?

Also, all of the validators take the same if/unless options, so you can make them conditional at will.

Update: Looking back at this answer a few days later, I see that I should explain why it works:

  • If you set a validator's :unless option to be a symbol, Rails will look for an instance method of that name, invoke that method on the instance that's being validated -- at validation time -- and only perform the validation if the method returns false.
  • ActiveRecord automatically creates question mark methods for each of your model's attributes, so the existence of a home_phone column in your model's table causes Rails to create a handy #home_phone? method. This method returns true if and only if home_phone is present (i.e. not blank). If the home_phone attribute is nil or an empty string or a bunch of white space, home_phone? will return false.

UPDATE: Confirmed that this old technique continues to work in Rails 5.

Solution 2 - Ruby on-Rails

You must use a lambda / Proc object:

validates_presence_of :mobile_number, :unless => lambda { self.home_phone.blank? }

Solution 3 - Ruby on-Rails

Starting in Rails 4, you can pass a block to presence. Concisely:

validates :mobile_number, presence: {unless: :home_phone?}

Also, :home_phone? returns false for nil or blank.

Solution 4 - Ruby on-Rails

Here is another way that works in rails 4

  validates_presence_of :job, if: :executed_at?

  validates :code,
            presence: true,
            length:  { minimum: 10, maximum: 50 },
            uniqueness: { case_sensitive: false },
            numericality: { only_integer: true }

Solution 5 - Ruby on-Rails

a short solution:

validates_presence_of :mobile_number, unless: -> { home_phone.blank? }

Solution 6 - Ruby on-Rails

In newer versions of Rails, instead of relying on old validates_presence_of, you should use validates and list validations for each attribute:

validates :mobile_number, presence: { if: -> { home_phone.present? } }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRobert BView Question on Stackoverflow
Solution 1 - Ruby on-RailsRob DavisView Answer on Stackoverflow
Solution 2 - Ruby on-RailsRyan BiggView Answer on Stackoverflow
Solution 3 - Ruby on-RailsIAmNaNView Answer on Stackoverflow
Solution 4 - Ruby on-RailsChris HoughView Answer on Stackoverflow
Solution 5 - Ruby on-RailsJohnView Answer on Stackoverflow
Solution 6 - Ruby on-RailsshimeView Answer on Stackoverflow