2012-08-09 64 views
5

随着从Rails 2迁移到Rails 3,验证错误从ActiveRecord :: Error移动到了ActiveModel :: Errors。
在2验证错误轨道的A型和消息(除其他事项外),你可以通过执行类似检查验证错误的类型如下:如何确定ActiveModel :: Errors验证类型

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 

这是不是在所有的理想。

问:
是否有轨3.0更好的方式来确定验证错误的类型?

+0

的可能的复制[?如何测试该验证失败的ActiveRecord中(http://stackoverflow.com/questions/4119379/how-to-test-which-验证 - 失败 - 在积极记录) – lulalala 2016-03-18 07:33:31

回答

4

检查添加?加载ActiveModel上的错误:::

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

这可以让你做到这一点:

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

这将做的伎俩(虽然它也只是比较验证消息),但它没有被回溯到3.0(我没有具体提到,我会更新问题)。 – pricey 2012-10-30 08:18:36

+0

这是它依赖于翻译的文本消息的坏事。 – 2016-01-06 17:26:08

1

我需要它不仅用于测试目的,同时也为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)