我在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
端
系统正在运行,但我需要优化某些问题:
我是否可以在ValidationFunction中验证日期,而无需为每个命名不同的日期创建新函数(如def validate_buggy_start_date
)。有没有办法可以立即使用validate_date()
- 函数C_9(即无需通过validate_buggy_start_date)?
我想初始化参数,同时确保它们是float / string / date等,例如variable.to_date
。但是,我不能,因为初始化是在验证之前完成的,所以它会使应用程序崩溃。我现在通过在calculate_me()
- 函数中重新建立它来解决它,但它感觉不是很干。有没有办法解决这个问题?
由于某种原因,我无法理解,我需要将变量命名为与属性名称完全相同,例如@nbr_of_days
需要命名。如果我将其命名为@day_numbers
则不起作用(将不会设置该值)。为什么会这样?有更聪明的方法吗?
简而言之,如果可能的话,请帮助我让这个功能变得更聪明,更干!
答案 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