在Ruby和/或Rails中的哪里定义自定义错误类型?


149

是否有在Ruby库(gem)或Ruby on Rails应用程序中定义自定义错误类型的最佳实践?特别:

  1. 他们在结构上在哪里属于项目?是否在其他地方插入了一个与相关模块/类定义内联的单独文件?
  2. 有没有建立任何时候约定,当创建一个新的错误类型?

不同的库有不同的处理方式,我还没有注意到任何实际的模式。有些库始终使用自定义错误类型,而另一些则根本不使用它们。一些具有扩展StandardError的所有错误,而另一些具有嵌套的层次结构;有些只是空的类定义,有些则有各种各样的技巧。

哦,就是因为我觉得称这些“错误类型”有点模棱两可,所以我的意思是:

class AuthenticationError < StandardError; end
class InvalidUsername < AuthenticationError; end

Answers:


219

对于宝石

我见过很多次您以这种方式定义异常:

gem_dir / lib / gem_name / exceptions.rb

并定义为:

module GemName

  class AuthenticationError < StandardError; end
  class InvalidUsername < AuthenticationError; end

end

一个例子就是httparty中的类似内容

对于Ruby on Rails

将它们放在您的lib /文件夹下的名为exceptions.rb的文件下,该文件如下所示:

module Exceptions
  class AuthenticationError < StandardError; end
  class InvalidUsername < AuthenticationError; end
end

并且您可以这样使用它:

raise Exceptions::InvalidUsername

对于宝石,看起来您可能还必须包括例外文件。再次从以下示例中看到此示例httpartygithub.com/jnunemaker/httparty/blob/…–
Jason Swett

37
为什么将它们命名为Exceptions模块?
ABMagil

13
我认为那/lib可能不是出错的地方。它们是非常特定于应用程序的,我给我的印象是,我放入的/lib代码意味着可以在其他应用程序中重用的代码。
wuliwong

1
Ruby on Rails指令对我不起作用-在典型情况下,实际上需要加载此新文件吗?
Meekohi

1
@ABMagil似乎我必须否则Unable to autoload constant Exceptions, expected /app/lib/exceptions.rb to define it,其他选项将是我认为每个异常一个类
ryan2johnson9

25

我认为,为了在项目中包含具有凝聚力的源文件,您应该在类中定义错误,这些错误可能会将它们丢到其他地方。

某些层次结构可能会有所帮助-命名空间擅长将冗余字符串保留在类型名称之外-但这更多的是个人喜好问题-无需过多考虑,前提是您的应用中至少有一个自定义异常类型,您可以在整个过程中使用它来区分在“故意”和“偶然”例外情况之间。


8
从理论上来说你是对的,但是当完全不同的情况下,不同的类会引发相同的错误时,会发生什么呢?
阿兰(Alain)

1
@Alain为什么不在Exceptions / Errors模块中定义多个类使用的那些错误,而将所有其他错误保留在使用它们的单个类中?
Scott W

@ScottW,在这种情况下,我们依靠开发人员来记住检查。
Josh Saint Jacque

22

在rails中,您可以建立app/errors目录

# app/errors/foo_error.rb
class FooError < StandardError; end

重新启动spring / server,它应该接起来


我应该如何提出这些例外?
Nikhil Wagh

@NikhilWagh要么 raise FooError, "Example message..."还是raise FooError.new("Example message...")
schpet

13

这是一个古老的问题,但是我想分享一下我如何在Rails中处理自定义错误,包括附加错误消息,测试以及如何使用 ActiveRecord模型。

创建自定义错误

class MyClass
  # create a custome error
  class MissingRequirement < StandardError; end

  def my_instance_method
    raise MyClass::MissingRequirement, "My error msg" unless true   
  end
end

测试(最小)

test "should raise MissingRequirement if ____ is missing"
  # should raise an error
  error = assert_raises(MyClass::MissingRequirement) {
    MyClass.new.my_instance_method
  }

  assert error.message = "My error msg"
end

使用ActiveRecord

我认为值得注意的是,如果使用ActiveRecord模型,一种流行的模式是如下所述向模型添加错误,以使验证失败:

def MyModel < ActiveRecord::Base
  validate :code_does_not_contain_hyphens

  def code_does_not_contain_hyphens
    errors.add(:code, "cannot contain hyphens") if code.include?("-")
  end
end

运行验证时,此方法将搭载在ActiveRecord的 ActiveRecord::RecordInvalid错误类上,并导致验证失败。

希望这可以帮助!


9

为了确保自动加载可以在Rails 4.1.10中针对多个自定义错误类按预期进行,您需要为每个类分别指定单独的文件。这应该在开发中通过动态重新加载来工作。

这是我在最近的项目中设置错误的方式:

lib/app_name/error/base.rb

module AppName
    module Error
        class Base < StandardError; end
    end
end

以及随后的自定义错误,例如 lib/app_name/error/bad_stuff.rb

module AppName
    module Error
        class BadStuff < ::AppName::Error::Base; end
    end
end

然后,您应该可以通过以下方式调用错误:

 raise AppName::Error::BadStuff.new("Bad stuff just happened")

而且,如果您不想为每个新错误输入一个单独的文件,只需将它们全部放入lib/app_name/error.rb
jlhonora

得到一个uninitialized constant MyController::AppName。我正在呼叫控制器中的加薪
Nikhil Wagh,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.