优化此验证和初始化

时间:2016-08-20 10:45:31

标签: ruby-on-rails validation

我在Rails 4.2网站上有一个非常特殊的解决方案,我有许多复杂的计算。我考虑过验证和初始化的问题。

我为每个计算创建一个单独的类,所有看起来几乎都是相同的,如下所示(代码简化为更容易忽略)。因为我之前没有做过类似的事情,所以我在这里有点冰冷,其中一些是“试错编程”,但它确实有用。

我正在使用控制器等中的代码,使用这样的PUT请求:

C_9.calculate_me(params)

params看起来像这样:

{"utf8"=>"✓", "_method"=>"put", "authenticity_token"=>"...", "start_date"=>"2016-08-20", "nbr_of_days"=>"90", "commit"=>"Calculate", "controller"=>"calculations", "action"=>"result", "id"=>"9"}

代码

class C_9
  include ActiveModel::Validations  
  include ValidationFunctions     

  attr_accessor :start_date, :nbr_of_days
  validates_length_of :start_date, :minimum => 8, :message => "value_is_not_a_proper_date"  
  validates_numericality_of :nbr_of_days, :greater_than => 0, :message => "value_must_be_number_over_zero"
    validate :validate_buggy_start_date   

  def initialize(params = {}, options = {}) 
    @start_date = params[:start_date]
    @nbr_of_days = params[:nbr_of_days]
  end 

  def calculate_me(params)
    @start_date = @start_date.to_date

      result_date = @start_date +  @nbr_of_days.day    
  end   

end

验证功能

这些是许多不同计算中常用的验证函数。

    def validate_buggy_start_date # Don't know why the validate_start_date will not work for this...
        errors.add(:start_date, 'value_is_not_a_proper_date') unless validate_date(start_date)
    end

  def validate_date(this_date)
    begin
      Date.parse(this_date)
      this_date.to_date
    rescue
      proper_date = false
    else   
      proper_date = true
    end

我需要帮助

系统正在运行,但我需要优化某些问题:

  1. 我是否可以在ValidationFunction中验证日期,而无需为每个命名不同的日期创建新函数(如def validate_buggy_start_date)。有没有办法可以立即使用validate_date() - 函数C_9(即无需通过validate_buggy_start_date)?

  2. 我想初始化参数,同时确保它们是float / string / date等,例如variable.to_date。但是,我不能,因为初始化是在验证之前完成的,所以它会使应用程序崩溃。我现在通过在calculate_me() - 函数中重新建立它来解决它,但它感觉不是很干。有没有办法解决这个问题?

  3. 由于某种原因,我无法理解,我需要将变量命名为与属性名称完全相同,例如@nbr_of_days需要命名。如果我将其命名为@day_numbers则不起作用(将不会设置该值)。为什么会这样?有更聪明的方法吗?

  4. 简而言之,如果可能的话,请帮助我让这个功能变得更聪明,更干!

2 个答案:

答案 0 :(得分:1)

扩展SteveTurczyn的答案:(无需修补ActiveRecord :: Base)

您可以为ActiveRecord模型创建自定义验证程序。 See the guides

所以在你的情况下,这将是一个解决方案:

# app/models/date_validator.rb
class DateValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    Date.parse(value.to_s)
  rescue ArgumentError
    record.errors[attribute] << "value_is_not_a_proper_date"
  end
end

然后在模型中使用验证器:

# app/models/c_9.rb
class C_9
  include ActiveModel::Validations
  validates_with DateValidator, attributes: [:start_date]
end

使用示例:

c = C_9.new(start_date: "2016-12-12", end_date: "2014-01-22")
c.valid? # => false
c.start_date # => Mon, 12 Dec 2016 (Date object)
c.other_date = "2016-07-23"
c.valid? # => true
c.other_date # => Sat, 23 Jul 2016

答案 1 :(得分:0)

您可以创建自己的验证,而不仅仅是验证方法。那会让你做...

validates_buggy_date :start_date, :end_date, :other_date

创建文件config / initializers / validates_buggy_date.rb

ActiveRecord::Base.class_eval do
  def self.validates_buggy_date(*columns)
    validates_each(columns, {}) do |record, attribute, value|
      begin
        Date.parse(value)
        value.to_date
      rescue
        record.errors[attribute] << 'value_is_not_a_proper_date'
      end
    end
  end
end