使用参数提升自定义异常

Chr*_*ele 46 ruby exception-handling ruby-on-rails exception

我在rails中的模型上定义一个自定义Exception作为一种包装异常:( begin[code]rescue[raise custom exception]end)

当我提出异常时,我想传递一些关于a)内部函数引发错误的模型实例,以及b)捕获的错误的信息.

这是一个模型的自动导入方法,该方法由来自外部数据源的POST请求填充.

tldr; 如果您自己定义Exception,如何将参数传递给Exception?我在该Exception上有一个初始化方法,但raise语法似乎只接受一个Exception类和消息,没有传递给实例化过程的可选参数.

pho*_*oet 68

使用new创建例外实例:

class CustomException < StandardError
  def initialize(data)
    @data = data
  end
end
# => nil 
raise CustomException.new(bla: "blupp")
# CustomException: CustomException
Run Code Online (Sandbox Code Playgroud)

  • 我已经使用了一年了,我想补充一下:现在每次我想这样做而忘记怎么做,我看看[cancan的例外](https://github.com/ryanb/ cancan/blob/master/lib/cancan/exceptions.rb)提醒自己.对于更复杂的异常,最后一个错误遵循非常好的形式. (26认同)
  • 你应该总是添加`message = nil`作为你的第一个参数并调用`super(message)`否则就像`raise CustomError,:some_message`将不会正确设置消息. (4认同)

Max*_*ace 15

解:

class FooError < StandardError
  attr_reader :foo

  def initialize(foo)
   super
   @foo = foo
  end
end
Run Code Online (Sandbox Code Playgroud)

如果您遵循Rubocop样式指南并且始终将您的消息作为第二个参数传递给raise:这是最好的方法:

raise FooError.new('foo'), 'bar'
Run Code Online (Sandbox Code Playgroud)

你可以foo这样:

rescue FooError => error
  error.foo     # => 'foo'
  error.message # => 'bar'
Run Code Online (Sandbox Code Playgroud)

如果要在其中定义错误消息,请foo写入:

class FooError < StandardError
  attr_reader :foo

  def initialize(foo)
   super
   @foo = foo
  end

  def message
    "The foo is: #{foo}"
  end
end
Run Code Online (Sandbox Code Playgroud)

说明:

将您的消息作为第二个参数传递给 foo

正如Rubocop样式指南所说,消息和异常类应该作为单独的参数提供,因为如果你写:

raise FooError.new('bar')
Run Code Online (Sandbox Code Playgroud)

并且想要传递一个回溯raise,没有两次传递消息就没有办法做到这一点:

raise FooError.new('bar'), 'bar', other_error.backtrace
Run Code Online (Sandbox Code Playgroud)

正如这个答案所说,如果你想将异常重新引发为具有相同回溯和不同消息或数据的新实例,则需要传递回溯.

raise,打电话FooError,而不是foo

以下是FooError使用Pry运行的测试代码实现的三种不同方法:

raise FooError.new('foo'), 'bar', backtrace # case 1
Run Code Online (Sandbox Code Playgroud)

raise'bar'消息未正确设置,raise正确的实现也是如此.


cyr*_*ier 9

以下是向错误添加代码的示例代码:

class MyCustomError < StandardError
    attr_reader :code

    def initialize(code)
        @code = code
    end

    def to_s
        "[#{code}] #{super}"
    end
end
Run Code Online (Sandbox Code Playgroud)

并提出它: raise MyCustomError.new(code), message


Lem*_*Cat 5

TL;DR 这个问题 7 年后,我相信正确的答案是:

class CustomException < StandardError
  attr_reader :extra
  def initialize(message=nil, extra: nil)
    super(message)
    @extra = extra
  end
end
# => nil 
raise CustomException.new('some message', extra: "blupp")
Run Code Online (Sandbox Code Playgroud)

警告:您将获得相同的结果:

raise CustomException.new(extra: 'blupp'), 'some message'
Run Code Online (Sandbox Code Playgroud)

但那是因为Exception#exception(string)做了一个#rb_obj_cloneon self,然后调用exc_initialize(它不调用CustomException#initialize。来自error.c

raise CustomException.new(extra: 'blupp'), 'some message'
Run Code Online (Sandbox Code Playgroud)

在后面的示例中#raise向上的上方,一个CustomException将被raise与D-message设置为“消息”和extra设置为“blupp”(因为它是一个克隆),但TWO CustomException第一条件:对象实际上创建CustomException.new通过,而第二#raise呼叫#exception的第一个实例CustomException创建了第二个克隆的CustomException.

我的扩展舞蹈混音版本为什么在:https : //stackoverflow.com/a/56371923/5299483