RubyやRailsでカスタムエラータイプを定義する場所


149

Rubyライブラリ(gem)またはRuby on Railsアプリケーションでカスタムエラータイプを定義するためのベストプラクティスはありますか?具体的には:

  1. 彼らはプロジェクトのどこに構造的に属していますか?別の場所に、関連するモジュール/クラス定義をインライン化した別のファイル?
  2. 新しいエラータイプ作成するタイミング作成しないタイミング規定する規則はありますか?

ライブラリが異なれば、実行方法も異なります。実際のパターンには気づきませんでした。一部のライブラリは常にカスタムエラータイプを使用しますが、他のライブラリはまったく使用しません。StandardErrorを拡張するすべてのエラーがあるものもあれば、階層がネストされているものもあります。空のクラス定義であるものもあれば、あらゆる種類の巧妙なトリックがあるものもあります。

ああ、そして私がこれらの「エラータイプ」を呼ぶのがちょっと曖昧だと感じたからといって、私が意味するのはこれです:

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

回答:


219

宝石用

私はあなたが例外をこのように定義することを何度も見ました:

gem_dir / lib / gem_name / exceptions.rb

次のように定義されます:

module GemName

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

end

この例は、httpartyのこのようなものです。

Ruby on Railsの場合

これらを、次のように見えるexceptions.rbというファイルの下のlib /フォルダーに配置します。

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

次のように使用します。

raise Exceptions::InvalidUsername

宝石の場合、例外ファイルも含める必要があるようです。もう一度この例を参照してくださいhttpartygithub.com/jnunemaker/httparty/blob/…–
Jason Swett

37
それらの名前空間をExceptionsモジュールに入れるのはなぜですか?
ABMagil 2015年

13
/libエラーの場所ではないかもしれません。それらは非常にアプリケーション固有であり、私が入れ/libているコードは他のアプリケーションで再利用できるコードであることを意図していると私は感じています。
ウリウォン2017年

1
Ruby on Railsの命令は機能しませんでした-通常、この新しいファイルを実際にロードするために追加の手順が必要ですか?
Meekohi

1
@ABMagilは、私がそうでなければUnable to autoload constant Exceptions, expected /app/lib/exceptions.rb to define it、他のオプションは、例外ごとに1つのクラスになると思います
ryan2johnson9

25

私はあなたのプロジェクトにまとまりのあるソースファイルを持たせるために、クラスでエラーを定義して、それらを他のどこにもスローしないようにする必要があると思います。

いくつかの階層が役立つ可能性があります-名前空間は冗長な文字列を型名から遠ざけるのに優れています-しかし、それは好みの問題です-区別するために全体を通して使用するアプリに少なくとも1つのカスタム例外型があれば、やり過ぎる必要はありません「意図的」と「偶発的」の例外ケースの間。


8
理論的には正しいが、まったく異なる状況でさまざまなクラスによって同じエラーが発生する可能性がある場合はどうなりますか?
アラン

1
@Alainなぜ、Exceptions / Errorsモジュールで複数のクラスによって使用されるエラーを定義し、他のすべてのエラーをそれらを使用する単一のクラスで定義したままにしないのですか?
スコットW

@ScottW、その場合、チェックすることを覚えておくのは開発者に任せています。
Josh Saint Jacque 2017

22

レールではapp/errorsディレクトリを作成できます

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

春/サーバーを再起動し、それをピックアップする必要があります


これらの例外をどのように発生させる必要がありますか?
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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.