在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

谢谢

Answers:


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只捕获所有类型的块呢?
Matrix

7
@RonLugge它完全取决于当前的情况。凭经验应用“从不”是一个坏主意。
贾斯汀·斯基尔斯

11
@JustinSkiles捕获异常将捕获语法错误(以及中断信号)。给我一个在生产代码中执行此操作的好方案。我可以直接捕获信号,但是您需要明确地这样做以使您清楚地创建信号处理程序。只是捕获E​​xception ...坏,坏主意。捕捉甚至不该抓的东西。
RonLugge 2015年

6
从Exception抢救的少数几种常见情况之一是出于日志记录/报告的目的,在这种情况下,您应该立即引发异常:stackoverflow.com/a/10048406/252346
aelesbao,2017年

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 2012年

如果我在没有参数的情况下使用raid_from?那会和救援一样吗?抓住所有错误?
minohimself

2
这不是坏习惯rescue_from Exception吗?我的理解是,最好从中进行救助StandardError,以便诸如SyntaxErrorLoadError不被捕获。
lobati 2014年

是的,抢救“异常”是一种不好的形式。请参阅Avdi Grimm的“ Exceptional Ruby”,以了解这可能会引起问题的原因。
Midwire

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/...
蒂博BARRERE

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 2014年

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

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.