【问题标题】:Validate presence of one field or another (XOR)验证一个字段或另一个字段的存在 (XOR)
【发布时间】:2022-04-19 15:57:54
【问题描述】:

如何验证一个或另一个字段的存在,但不能同时验证至少一个?

【问题讨论】:

    标签: ruby-on-rails


    【解决方案1】:

    如果您将条件添加到数值验证中,您的代码将起作用,如下所示:

    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
    

    【讨论】:

    • 这个功能很好用。但是,我无法得到表单页面上显示的错误。除非我在我的 _form.slim 上执行类似 ´= @invoice.errors[:base][0]` 的操作。有什么建议吗?
    【解决方案2】:

    我认为这在 Rails 中更惯用:

    例如:用于验证 user_nameemail 之一是否存在:

    validates :user_name, presence: true, unless: ->(user) { user.email.present? }
    validates :email, presence: true, unless: ->(user) { user.user_name.present? }
    

    【讨论】:

    • 这不处理“不是两个”标准
    • 另一个缺点,使用这种方法,如果两个字段都留空,则会向用户显示两个稍微误导性的错误:“电子邮件不能为空”和“用户名不能为空”。最好显示一个错误(根据接受的答案),至少必须提供其中一个解释。
    【解决方案3】:
    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
    

    您甚至可以使用 3 个或更多值来做到这一点:

    if [month_day, week_day, hour].compact.count != 1
    

    【讨论】:

      【解决方案4】:

      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
      

      【讨论】:

        【解决方案5】:

        使用Proc or Symbol with :if and :unless 的验证将在验证发生之前被调用。

        所以存在两个字段之一可能是这样的:

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

        (示例 sn-p)代码具有 :if:unless 作为最新项目,但是正如 doc 中声明的那样,它将在验证发生之前被调用 - 因此,如果条件匹配,将在之后进行另一次检查。

        【讨论】:

        • 这种方法的缺点是,如果两个字段都留空,则会向用户显示两个稍微误导性的错误:“费用不能为空白”和“付款不能为空白”。最好显示一个错误(根据接受的答案),至少必须提供其中一个解释。
        【解决方案6】:
         validate :father_or_mother
        

        #父亲姓氏或母亲姓氏为必填项

         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
        

        试试上面的简单例子。

        【讨论】:

          【解决方案7】:

          我把我对这个问题的回答放在下面。在此示例中,:description:keywords 是其中一个不能为空的字段:

            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
          

          【讨论】:

            猜你喜欢
            • 2020-02-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-01-11
            • 1970-01-01
            • 2011-09-20
            • 2018-09-22
            相关资源
            最近更新 更多