Valider la présence d'un champ ou d'un autre (XOR)

91

Comment valider la présence d'un champ ou d'un autre mais pas des deux et d'au moins un?

Ben Orozco
la source

Réponses:

154

Votre code fonctionnera si vous ajoutez des conditions aux validations de numéricité comme ceci:

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
      unless charge.blank? ^ payment.blank?
        errors.add(:base, "Specify a charge or a payment, not both")
      end
    end

end
art sémantique
la source
La fonctionnalité fonctionne très bien. Mais, je n'ai pas pu obtenir les erreurs affichées sur la page du formulaire. Sauf si je fais quelque chose comme ´ = @ facture.errors [: base] [0] `sur mon _form.slim. Aucune suggestion?
bir_ham
45

Je pense que c'est plus idiomatique dans Rails 3+:

Exemple: pour valider que l'un des éléments user_nameou emailest présent

validates :user_name, presence: true, unless: ->(user){user.email.present?}
validates :email, presence: true, unless: ->(user){user.user_name.present?}
jmanrubia
la source
27
Cela ne gère pas les critères "pas les deux"
Paul Pettengill
11
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
      if [charge, payment].compact.count != 1
        errors.add(:base, "Specify a charge or a payment, not both")
      end
    end

end

Vous pouvez même le faire avec 3 valeurs ou plus:

if [month_day, week_day, hour].compact.count != 1
Kieran Andrews
la source
10

Exemple de rails 3.

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

  validates_numericality_of :charge, :unless => proc{|obj| obj.charge.blank?}
  validates_numericality_of :payment, :unless => proc{|obj| obj.payment.blank?}


  validate :charge_xor_payment

  private

    def charge_xor_payment
      if !(charge.blank? ^ payment.blank?)
        errors[:base] << "Specify a charge or a payment, not both"
      end
    end
end
Seoman
la source
2
 validate :father_or_mother

# Le nom du père ou le nom de la mère est obligatoire

 def father_or_mother
        if father_last_name == "Last Name" or father_last_name.blank?
           errors.add(:father_last_name, "cant blank")
           errors.add(:mother_last_name, "cant blank")
        end
 end

Essayez ci-dessus un exemple simple.

chaitanya
la source
1

Je mets ma réponse à cette question ci-dessous. Dans cet exemple, :descriptionil :keywordsy a des champs dont l'un d'entre eux n'est pas vide:

  validate :some_was_present

  belongs_to :seo_customable, polymorphic: true

  def some_was_present
    desc = description.blank?
    errors.add(desc ? :description : :keywords, t('errors.messages.blank')) if desc && keywords.blank?
  end
Neodelf
la source
1

La validation utilisant un Proc ou un Symbole avec: si et: sauf sera appelée juste avant que la validation ne se produise.

Donc, la présence d'un des deux champs peut être comme ceci:

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

Le code (exemple d'extrait de code) a :ifou :unlesscomme dernier élément, mais comme déclaré dans le document, il sera appelé juste avant la validation - donc une autre vérification fonctionnera après, si la condition correspond.

oklas
la source