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?

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

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?}

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

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

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.


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

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.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.