Validate presence of one field or another (XOR)

Viewed 38847

How do I validate the presence of one field or another but not both and at least one ?

7 Answers

Your code will work if you add conditionals to the numericality validations like so:

class Transaction < ActiveRecord::Base
  validates_presence_of :date
  validates_presence_of :name

  validates_numericality_of :charge, allow_nil: true
  validates_numericality_of :payment, allow_nil: true

  validate :charge_xor_payment

  private

  def charge_xor_payment
    return if charge.blank? ^ payment.blank?

    errors.add(:base, 'Specify a charge or a payment, not both')
  end
end

Validation using a Proc or Symbol with :if and :unless will get called right before validation happens.

So presence one of both fields may be like this:

validates :charge,
  presence: true,
  if: ->(user){user.charge.present? || user.payment.present?}
validates :payment,
  presence: true,
  if: ->(user){user.payment.present? || user.charge.present?}

The (example snippet) code has :if or :unless as latest item, however as declared in doc it will get called right before validation happens - so another checking will works after, if condition match.

Related