为什么我无法挽救在另一个 class 中定义的这个自定义错误?

Why can't I rescue this custom error defined inside another class?

我在 Rails 6 中工作。我在引发它的 class 中定义了一个错误 class:

class MyClass < ApplicationRecord
  ...

  class CustomError < StandardError
    attr_reader :param

    def initialize(param)
      @param = param
    end
  end
end

我试图在客户端代码中拯救它,但这并没有捕捉到它:

rescue MyClass::CustomError => e

另一方面,这会在 CustomError 上引发 uninitialized constant,正如我所期望的那样:

rescue CustomError => e

这个呢?

rescue MyClass::CustomError => e
  raise unless e.instance_of? MyClass::CustomError
  # do some real error handling
  ...
end

instance_of? 无法识别错误并重新引发。

我什至尝试过:

class MyClass < ApplicationRecord
  ...
end

class MyClass::CustomError < StandardError
  attr_reader :para
  def initialize(param)
    @param = param
  end
end

再好不过了。

2 起作用的东西都是代码味道:

  1. 在包含 class 之外定义错误,没有命名空间

  2. 正在解决一般性错误:rescue => e

它在 MiniTest 中也能正常工作:

e = assert_raises(MyClass::CustomError) do
  ...
end

感觉错误 class 名称 CustomError 根本没有在应用程序代码中解析为 MyClass::CustomError,但客户端代码需要包含 class 名称才能完全解决 class。

更有可能,虽然我只是做了一些事情 naive/stupid!

附加信息:

对于任何不知道的人,Rails 4.2 添加了 Spring,它在您终止应用程序时将其保留在内存中(以加快启动时间),并且 Rails 5.2 添加了 Bootsnap,缓存优化代码。他们中的任何一个都可以保持不变的代码,因为奇怪的错误。

他们中的一个刚刚咬了我。似乎 Bootsnap 引发了错误,但没有让它在 MyClass 之外可见。删除缓存解决了所有问题:

rm -rf tmp/cache/bootsnap-compile-cache/
rm tmp/cache/bootsnap-load-path-cache