How to determine ActiveModel :: Type of error checking

When migrating from Rails 2 to Rails 3, validation errors were transferred from ActiveRecord :: Error to ActiveModel :: Errors.
On rails 2, the validation error was of type and message (by the way), and you could check the type of validation error by doing something like the following:

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

But with Rails 3, it seems that everything except the invalid attribute and message is lost. As a result, the only way to determine the type is to compare the error message:

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

Which is not at all ideal (for example, what if you have several validations that use the same message?).

Question:
Is there a better way in rails 3.0 to determine the type of validation error?

+5
source share
2
+4

, 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)
+1

All Articles