【问题标题】:How to add ruby on rails model validation for two fields?如何为两个字段添加 ruby​​ on rails 模型验证?
【发布时间】:2020-05-19 05:50:39
【问题描述】:
#  columns
#  maximum_users           :integer(4)
#  last_registration_date  :datetime

class Training < ApplicationRecord

 validates :maximum_users, numericality: { greater_than: 0, less_than_or_equal_to: 999,  
            only_integer: true }

 validate :last_reg_date_cannot_be_in_the_past



   private
   def last_reg_date_cannot_be_in_the_past
    if last_registration_date_changed? && last_registration_date < Time.now.utc
      errors.add(:training, "can't be in the past")
    end
  end

end

在上述模型中,我需要添加以下验证:

  1. 如果用户选择任何一个字段而不是其他字段应该为零(maximum_userslast_registration_date)。
  2. 用户不能同时添加两个字段值。
  3. 用户可以选择不选择任何值。但如果他当时选择,则必须允许任何字段。
  4. maximum_users 允许小于 999
  5. last_registration_date 必须大于今天的日期。

我添加了一些验证,但我认为这不是一个好的做法。

如何重构模型以涵盖上述所有场景?

【问题讨论】:

  • 我建议您在 1 个自定义验证中执行此操作,因为您可以在那里验证两个字段。
  • 对于上述场景,这将是一个漫长的验证过程。有没有办法缩短这些?
  • 我认为唯一可以通过validates 使用的规则是第4,也许是第5。其他人必须是自定义的,所以我建议在自定义验证中完成所有操作。是的,它会很长,但更具可读性和可维护性。但也许我错了,可以通过validates
  • 您也许可以对每一列进行一些条件验证。就像验证存在一样,如果 ... guides.rubyonrails.org/…
  • @vikas95prasad RE:“这将是一个冗长的验证”——是的,这就是为什么我还建议使用自定义验证而不是尝试用“聪明”来内联所有这些(但令人困惑和容易出错)if: [Proc.new(...), ...] 逻辑。更具体地说,我建议定义一个custom validator class,您可以在其中将所有这些逻辑(尤其是要求 1-3)拆分为干净的方法,并单独编写/测试它们。

标签: ruby-on-rails ruby validation ruby-on-rails-4 activerecord


【解决方案1】:

进行大量验证并不是一个坏习惯。在某些时候,您可能希望将其移至验证器类。

class Training < ApplicationRecord
 validates_with TrainingValidator
end

我看到的一个问题是,last_registration_date 可以设置,maximum_users 为 nil,但上面的 maximum_users 验证可能不允许 nil。

app/models/concerns/traning_validator.rb

classTrainingValidator < ActiveModel::Validator 

  def validate(training)
    if training.last_registration_date_changed? && training.last_registration_date < Time.now.utc
      training.errors.add(:training, "can't be in the past")
    end

    unless training.last_registration_date.nil? || training.maximum_users.nil?
      training.errors.add(:last_registration_date, "last_registration_date cannot both be set when maximum_users is set")
    end

    unless training.maximum_users.nil? || training.maximum_users < 999
      training.errors.add(:maximum_users, "must be less than 999")
    end
  end
end

【讨论】:

  • 您能否建议对我的解决方案进行更改@Marlin
  • 相同的代码,但使用像你一样的私有方法。
【解决方案2】:

我做了这样的事情:

class NotInPastValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    record.errors.add attribute, (options[:message] || "Date can't be in the past") if value <= Time.now.utc
  end
end

型号:

 validates :maximum_users,
            numericality: {
              greater_than: 0,
              less_than_or_equal_to: 999,
              only_integer: true
            }
  validates :last_registration_date, not_in_past: true
  validate :validate_max_users_and_last_reg_date


  def validate_max_users_and_last_reg_date
    if maximum_users_changed? && last_registration_date_changed?
      errors.add(:training, 'Specify either maximum users or last registration date, not both')
    end
  end

  def maximum_users_changed?
    changes.keys.include? 'maximum_users'
  end

  def last_registration_date_changed?
    changes.keys.include? 'last_registration_date'
  end

【讨论】:

    猜你喜欢
    • 2016-08-04
    • 1970-01-01
    • 1970-01-01
    • 2021-03-21
    • 2012-12-19
    • 1970-01-01
    • 2012-06-21
    • 1970-01-01
    • 2023-03-22
    相关资源
    最近更新 更多