如何知道发生Ruby Exception的对象

时间:2013-04-03 05:22:06

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

我相信在发生异常的大多数情况下,它们确实发生在对象周围,因为尝试在对象上调用方法,或者在执行某些代码时发生,这些代码属于属于某个方法的某个方法的一部分。对象

我是如何从给定的Exception实例中了解此对象的?

实施例

begin
  ....
rescue ActiveRecord::SerializationTypeMismatch => e
  object = e.some_method_which_will_return_active_record_object
rescue => e
  object = e.get_me_object_around_which_this_happened
end

在我的特定情况下,我想知道发生了哪个AR对象SerializationTypeMismatch。

在这种情况下我对e.message或backtrace不感兴趣,我也检查了e.methods,但没有找到解决相关对象的方法。

1 个答案:

答案 0 :(得分:2)

  

我相信在发生异常的大多数情况下,它们确实发生在对象周围,因为尝试在对象上调用方法,或者在执行某些代码时发生,这些代码属于属于某个方法的某个方法的一部分。对象

但是在所有情况下都不是这样,并且通常在引发的Exception和它周围发生的对象之间没有任何关系,因为可能并不总是存在对象。

例如,当无法加载所需文件(例如Ruby脚本)时,会引发LoadError。这与任何特定的对象实例都没有关系。我不相信任何standard exception classes的初始化方法接受存储与该异常相关的对象的参数,因此没有直接的方法来映射回原始对象。

如果您无法映射回发生错误的ActiveRecord对象,则可能是您的begin / rescue块在被调用的代码堆栈中“过高”。例如,您的each块中可能包含此begin循环:

begin
  items.each do |item|
    raise RuntimeError unless item == "foo"
  end
rescue RuntimeError => e
  # which item caused the error?
end

在这种情况下,您无法知道哪个项导致了错误,但您可以重构begin块以更直接地包装代码,如下所示:

items.each do |item|
  begin
    raise RuntimeError unless item == "foo"
  rescue RuntimeError => e
    # the object that raised the exception must be 'item'
  end
end

这当然是一个人为的例子,但希望它说明了将begin / rescue块更紧密地包裹在可能引发异常的代码周围的技术,因此对于哪个对象没有歧义引起了这个问题。