从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中有更好的方法来确定验证错误的类型吗?
答案 0 :(得分:4)
检查是否已添加?在ActiveModel ::错误:
https://github.com/rails/rails/blob/master/activemodel/lib/active_model/errors.rb#L331
允许你这样做:
record.errors.added?(:field, :error)
答案 1 :(得分: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)