【问题标题】:How to determine ActiveModel::Errors validation type如何确定 ActiveModel::Errors 验证类型
【发布时间】:2012-08-09 10:04:16
【问题描述】:

随着从 Rails 2 到 Rails 3 的迁移,验证错误从 ActiveRecord::Error 移动到 ActiveModel::Errors。
在 rails 2 中,验证错误具有类型和消息(除其他外),您可以通过执行以下操作来检查验证错误的类型:

rescue ActiveRecord::RecordInvalid => e
  e.record.errors.each do |attr, error|
    if error.type == :foo
      do_something
    end
  end
end

但是在 Rails 3 中,除了无效属性和消息之外的所有内容似乎都丢失了。因此确定类型的唯一方法是比较错误消息:

rescue ActiveRecord::RecordInvalid => e
  e.record.errors.each do |attr, error|
    if error == "foobar"
      do_something
    end
  end
end

这根本不理想(例如,如果您有多个使用相同消息的验证怎么办?)。

问题:
在 rails 3.0 中是否有更好的方法来确定验证错误的类型?

【问题讨论】:

标签: ruby-on-rails-3 validation


【解决方案1】:

检查是否添加?在 ActiveModel::Errors 上:

https://github.com/rails/rails/blob/master/activemodel/lib/active_model/errors.rb#L331

这允许你这样做:

record.errors.added?(:field, :error)

【讨论】:

  • 这可以解决问题(尽管它也只是比较验证消息),但它还没有被向后移植到 3.0(我没有特别提到,我会更新问题)。
  • 它的坏处在于它依赖于翻译的短信。
【解决方案2】:

我不仅需要它用于测试目的,还需要它用于 API。我最终得到了猴子补丁:

module CoreExt
  module ActiveModel
    module Errors
      # When validation on model fails, ActiveModel sets only human readable
      # messages. This does not allow programmatically identify which
      # validation rule exactly was violated.
      #
      # This module patches {ActiveModel::Errors} to have +details+ property,
      # that keeps name of violated validators.
      #
      # @example
      #   customer.valid? # => false
      #   customer.errors.messages # => { email: ["must be present"] }
      #   customer.errors.details # => { email: { blank: ["must be present"] } }
      module Details
        extend ActiveSupport::Concern

        included do
          if instance_methods.include?(:details)
            fail("Can't monkey patch. ActiveModel::Errors already has method #details")
          end

          def details
            @__details ||= Hash.new do |attr_hash, attr_key|
              attr_hash[attr_key] = Hash.new { |h, k| h[k] = [] }
            end
          end

          def add_with_details(attribute, message = nil, options = {})
            error_type = message.is_a?(Symbol) ? message : :invalid
            normalized_message = normalize_message(attribute, message, options)
            details[attribute][error_type] << normalized_message

            add_without_details(attribute, message, options)
          end
          alias_method_chain :add, :details

          def clear_with_details
            details.clear
            clear_without_details
          end
          alias_method_chain :clear, :details
        end
      end
    end
  end
end

# Apply monkey patches
::ActiveModel::Errors.send(:include, ::CoreExt::ActiveModel::Errors::Details)

【讨论】:

    猜你喜欢
    • 2020-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-02
    • 2014-04-05
    相关资源
    最近更新 更多