Fangen Sie alle Ausnahmen in einem Rails Controller ab

89

Gibt es eine Möglichkeit, alle nicht abgefangenen Ausnahmen in einem Rails-Controller wie folgt abzufangen:

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

Danke dir

Neigaard
quelle

Antworten:

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
Chris Johnsen
quelle
38
Ist es nicht die Regel, NIEMALS eine Ausnahme zu erwischen?
RonLugge
2
aber wie kann ich alle rescue => etypen nur im block fangen ?
Matrix
7
@ RonLugge es hängt ganz von der jeweiligen Situation ab. Als Faustregel "nie" anzuwenden ist eine schlechte Idee.
Justin Skiles
11
@JustinSkiles Catching Exception erkennt Syntaxfehler (und unterbricht auch Signale). Geben Sie mir ein gutes Szenario dafür im Produktionscode. Ich kann Signale direkt abfangen, aber Sie müssen dies explizit tun, um zu verdeutlichen, dass Sie einen Signalhandler erstellen. Nur Ausnahme fangen ... schlechte, schlechte Idee. Fängt sogar die Dinge, die Sie nicht fangen sollten.
RonLugge
6
Einer der wenigen Fälle, in denen es sinnvoll ist
aelesbao
197

Sie können auch eine Rettungsmethode definieren.

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

Abhängig von Ihrem Ziel möchten Sie möglicherweise auch erwägen, Ausnahmen NICHT pro Controller zu behandeln. Verwenden Sie stattdessen so etwas wie das Juwel " exception_handler" , um Antworten auf Ausnahmen konsistent zu verwalten. Als Bonus werden bei diesem Ansatz auch Ausnahmen behandelt, die auf der Middleware-Ebene auftreten, z. B. das Analysieren von Anforderungen oder Datenbankverbindungsfehler, die Ihre Anwendung nicht sieht. Das Juwel " exception_notifier" könnte ebenfalls von Interesse sein.

BOFH
quelle
4
Dies ist noch praktischer, da Ausnahmen auf trockene Weise abgefangen werden können.
m33lky
Und wenn ich Rescue_From ohne Parameter benutze? Wird sich das genauso verhalten wie Rettung? alle Fehler abfangen?
Minohimself
2
Ist es nicht schlecht zu üben rescue_from Exception? Mein Verständnis ist, dass es besser ist, sich zu retten StandardError, damit Dinge wie SyntaxErrorund LoadErrornicht gefangen werden.
Lobati
Ja, es ist eine schlechte Form, 'Ausnahme' zu retten. Siehe Avdi Grimms "Exceptional Ruby" für die Gründe, warum dies problematisch sein kann.
Midwire
34

Sie können Ausnahmen nach Typ abfangen:

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
mohamed-ibrahim
quelle
2
Achten Sie darauf, nicht Exceptiondirekt zu retten ; siehe stackoverflow.com/questions/10048173/…
Thibaut Barrère
10

rescue Ohne Argumente wird jeder Fehler behoben.

Also wirst du wollen:

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
PreciousBodilyFluids
quelle
8
Veraltete Frage, aber diese Antwort ist falsch. Rettung ohne Argument behandelt nur StandardError robots.thoughtbot.com/rescue-standarderror-not-exception
Keith Gaddis
0

Wenn Sie wirklich alles abfangen möchten, erstellen Sie einfach Ihre eigene Ausnahme-App, mit der Sie das Verhalten anpassen können, das normalerweise von der PublicExceptions-Middleware verarbeitet wird: https://github.com/rails/rails/blob/4-2 -stable / actionpack / lib / action_dispatch / middleware / public_exceptions.rb

Eine Reihe anderer Antworten teilen Edelsteine, die dies für Sie tun, aber es gibt wirklich keinen Grund, warum Sie sie nicht einfach ansehen und selbst tun können.

Eine Einschränkung: Stellen Sie sicher, dass Sie in Ihrem Ausnahmebehandler niemals eine Ausnahme auslösen. Andernfalls erhalten Sie eine hässliche FAILSAFE_RESPONSE https://github.com/rails/rails/blob/4-2-stable/actionpack/lib/action_dispatch/middleware/show_exceptions.rb#L4-L22

Übrigens kommt das Verhalten in der Steuerung von einem abrufbaren: https://github.com/rails/rails/blob/4-2-stable/activesupport/lib/active_support/rescuable.rb#L32-L51

BF4
quelle