Railsコントローラーですべての例外をキャッチする


89

次のように、Railsコントローラでキャッチされていないすべての例外をキャッチする方法はありますか?

def delete
  schedule_id = params[:scheduleId]
  begin
    Schedules.delete(schedule_id)
  rescue ActiveRecord::RecordNotFound
    render :json => "record not found"
  rescue ActiveRecord::CatchAll
    #Only comes in here if nothing else catches the error
  end
  render :json => "ok"
end

ありがとうございました

回答:


92
begin
  # do something dodgy
rescue ActiveRecord::RecordNotFound
  # handle not found error
rescue ActiveRecord::ActiveRecordError
  # handle other ActiveRecord errors
rescue # StandardError
  # handle most other errors
rescue Exception
  # handle everything else
  raise
end

38
例外を絶対にキャッチしないというルールはありませんか?
RonLugge 2014年

2
しかし、どのようにすればすべてのタイプをrescue => eブロックでのみキャッチできますか?
マトリックス

7
@RonLuggeそれは手元の状況に完全に依存します。経験則として「決して」を適用することは悪い考えです。
ジャスティンスカイズ

11
@JustinSkiles Catching Exceptionは構文エラー(および割り込み信号も)をキャッチします。本番コードでこれを行うための良いシナリオを1つ教えてください。シグナルを直接キャッチすることはできますが、シグナルハンドラーを作成していることを明確にするために、明示的に行う必要があります。例外をキャッチしています...悪い、悪い考え。キャッチしてはいけないものもキャッチします。
RonLugge 2015

6
あなたは例外レイズ再すぐにする必要があり、その場合には、例外からの救出にそれの正気は、ロギング/レポート作成を目的としており、いくつかの一般的な例の一つ:stackoverflow.com/a/10048406/252346
aelesbao

198

rescue_fromメソッドを定義することもできます。

class ApplicationController < ActionController::Base
  rescue_from ActionController::RoutingError, :with => :error_render_method

  def error_render_method
    respond_to do |type|
      type.xml { render :template => "errors/error_404", :status => 404 }
      type.all  { render :nothing => true, :status => 404 }
    end
    true
  end
end

目的によっては、コントローラーごとに例外を処理しないことも検討してください。代わりに、exception_handler gem などを使用して、例外への応答を一貫して管理します。おまけとして、このアプローチは、リクエストの解析やアプリケーションが認識しないデータベース接続エラーなど、ミドルウェア層で発生する例外も処理します。exception_notifierの宝石にも興味があるかもしれません。


4
これは、DRY方式で例外をキャッチできるため、さらに便利です。
m33lky

そして、パラメーターなしでrescue_fromを使用する場合?それはレスキューと同じように動作しますか?すべてのエラーをキャッチしますか?
minohimself 2014年

2
悪い習慣じゃないrescue_from Exceptionですか?私の理解では、それがよりよい救助にからであるということですStandardErrorので、のようなものSyntaxErrorとはLoadError捉えていません。
ロバティ2014

はい、「例外」を救うのは悪い形です。これが問題になる理由については、Avdi Grimmの「Exceptional Ruby」を参照してください。
Midwire、2015年

34

タイプごとに例外をキャッチできます。

rescue_from ::ActiveRecord::RecordNotFound, with: :record_not_found
rescue_from ::NameError, with: :error_occurred
rescue_from ::ActionController::RoutingError, with: :error_occurred
# Don't resuce from Exception as it will resuce from everything as mentioned here "http://stackoverflow.com/questions/10048173/why-is-it-bad-style-to-rescue-exception-e-in-ruby" Thanks for @Thibaut Barrère for mention that
# rescue_from ::Exception, with: :error_occurred 

protected

def record_not_found(exception)
  render json: {error: exception.message}.to_json, status: 404
  return
end

def error_occurred(exception)
  render json: {error: exception.message}.to_json, status: 500
  return
end

2
Exception直接救助しないように注意してください。stackoverflow.com/questions/10048173/…を
ThibautBarrère16年

10

rescue 引数を指定しないと、エラーが発生しなくなります。

したがって、次のものが必要になります。

def delete
  schedule_id = params[:scheduleId]
  begin
    Schedules.delete(schedule_id)
  rescue ActiveRecord::RecordNotFound
    render :json => "record not found"
  rescue
    #Only comes in here if nothing else catches the error
  end
  render :json => "ok"
end

8
古い質問ですが、この答えは正しくありません。引数なしのレスキューは、StandardError robots.thoughtbot.com/rescue-standarderror-not-exception
Keith Gaddis

0

実際、すべてをキャッチしたい場合は、独自の例外アプリを作成するだけで、PublicExceptionsミドルウェアによって通常処理される動作をカスタマイズできます。https//github.com/rails/rails/blob/4-2 -stable / actionpack / lib / action_dispatch / middleware / public_exceptions.rb

他の多くの答えはあなたのためにこれを行う宝石を共有していますが、あなたがそれらを見て自分でそれを行うことができない理由は本当にありません。

警告:例外ハンドラーで例外を発生させないようにしてください。そうしないと、醜いFAILSAFE_RESPONSE https://github.com/rails/rails/blob/4-2-stable/actionpack/lib/action_dispatch/middleware/show_exceptions.rb#L4-L22

ところで、コントローラーの動作はレスキュー可能から来ていますhttps : //github.com/rails/rails/blob/4-2-stable/activesupport/lib/active_support/rescuable.rb#L32-L51

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.