【问题标题】:Raising errors in attribute accessor overrides?在属性访问器覆盖中引发错误?
【发布时间】:2012-10-08 23:42:50
【问题描述】:

我正在重写 ActiveRecord 中的属性访问器,以将格式为“hh:mm:ss”的字符串转换为秒。这是我的代码:

class Call < ActiveRecord::Base
  attr_accessible :duration

  def duration=(val)
    begin
      result = val.to_s.split(/:/)
             .map { |t| Integer(t) }
             .reverse
             .zip([60**0, 60**1, 60**2])
             .map { |i,j| i*j }
             .inject(:+)
    rescue ArgumentError
      #TODO: How can I correctly report this error?
      errors.add(:duration, "Duration #{val} is not valid.")
    end
    write_attribute(:duration, result)
  end

  validates :duration, :presence => true,
                       :numericality => { :greater_than_or_equal_to => 0 }

  validate :duration_string_valid

  def duration_string_valid
    if !duration.is_valid? and duration_before_type_cast
      errors.add(:duration, "Duration #{duration_before_type_cast} is not valid.")
    end
  end
end

我正在尝试在验证期间有意义地报告此错误。我的前两个想法包含在代码示例中。

  1. 在访问器覆盖中添加错误 - 可以,但我不确定这是否是一个不错的解决方案。
  2. 使用验证方法duration_string_valid。检查其他验证是否失败并报告 duration_before_type_cast。在这种情况下,duration.is_valid? 不是有效方法,我不确定如何检查持续时间是否已通过其他验证。
  3. 我可以在 duration=(val) 内设置一个实例变量并在 duration_string_valid 内报告它。

我希望得到一些关于这是否是执行此操作的好方法以及如何改进错误报告的反馈。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 attr


    【解决方案1】:

    首先,清理您的代码。将字符串到持续时间转换器移动到服务层。在lib/ 目录中创建StringToDurationConverter:

    # lib/string_to_duration_converter.rb
    class StringToDurationConverter
      class << self
        def convert(value)
          value.to_s.split(/:/)
             .map { |t| Integer(t) }
             .reverse
             .zip([60**0, 60**1, 60**2])
             .map { |i,j| i*j }
             .inject(:+)
        end
      end
    end
    

    第二,添加自定义DurationValidator验证器

    # lib/duration_validator.rb
    class DurationValidator < ActiveModel::EachValidator
      # implement the method called during validation
      def validate_each(record, attribute, value)
        begin
          StringToDurationConverter.convert(value)
        resque ArgumentError
          record.errors[attribute] << 'is not valid.'
        end
      end
    end
    

    你的模型看起来像这样:

    class Call < ActiveRecord::Base
      attr_accessible :duration
    
      validates :duration, :presence => true,
                           :numericality => { :greater_than_or_equal_to => 0 },
                           :duration => true
    
      def duration=(value)
        result = StringToDurationConverter.convert(value)
        write_attribute(:duration, result)
      end
    end
    

    【讨论】:

    • 很好的答案。但是,我们不能在持续时间上有两个冲突的验证器 - DurationValidator 和 NumericalityValidator。 Duration 是一个可以由 DurationValidator 验证的哈希。我们不能同时使用数值验证器来验证持续时间为秒数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 2019-10-13
    • 1970-01-01
    • 2020-07-24
    • 2015-04-26
    • 2017-09-03
    相关资源
    最近更新 更多