Überprüfen Sie das Vorhandensein des einen oder anderen Felds (XOR).

91

Wie überprüfe ich das Vorhandensein des einen oder anderen Feldes, aber nicht beider und mindestens eines?

Ben Orozco
quelle

Antworten:

153

Ihr Code funktioniert, wenn Sie den Numerizitätsvalidierungen folgende Bedingungen hinzufügen:

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
Semanticart
quelle
Die Funktionalität funktioniert super. Die auf der Formularseite angezeigten Fehler konnten jedoch nicht angezeigt werden. Es sei denn, ich mache so etwas wie ´ = @ invoice.errors [: base] [0] `auf meinem _form.slim. Irgendwelche Vorschläge?
bir_ham
44

Ich denke, das ist in Rails 3+ idiomatischer:

zB: Um zu bestätigen, dass einer von user_nameoder emailvorhanden ist:

validates :user_name, presence: true, unless: ->(user){user.email.present?}
validates :email, presence: true, unless: ->(user){user.user_name.present?}
jmanrubia
quelle
27
Dies behandelt nicht die "nicht beide" Kriterien
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

Sie können dies sogar mit 3 oder mehr Werten tun:

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

Beispiel für Schienen 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
quelle
2
 validate :father_or_mother

#Vatername oder Mutter Nachname ist obligatorisch

 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

Versuchen Sie es oben mit einem einfachen Beispiel.

Chaitanya
quelle
1

Ich habe meine Antwort auf diese Frage unten gestellt. In diesem Beispiel :descriptionund :keywordssind Felder, von denen eines nicht leer ist:

  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
quelle
1

Validierung mit einem Proc oder Symbol mit: if und: es sei denn wird unmittelbar vor der Validierung aufgerufen.

Die Präsenz eines der beiden Felder kann also so aussehen:

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

Der (Beispiel-Snippet-) Code hat :ifoder :unlessals neuestes Element, wird jedoch, wie in doc deklariert , unmittelbar vor der Validierung aufgerufen. Wenn die Bedingungen übereinstimmen, funktioniert danach eine weitere Überprüfung.

oklas
quelle