Cattura tutte le eccezioni in un controller rails


89

C'è un modo per catturare tutte le eccezioni non rilevate in un controller rails, come questo:

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

Grazie

Risposte:


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
La regola non è MAI catturare l'eccezione?
RonLugge

2
ma come posso catturare tutto il tipo rescue => esolo in blocco?
Matrix

7
@RonLugge dipende interamente dalla situazione a portata di mano. applicare "mai" come regola pratica è una cattiva idea.
Justin Skiles

11
@JustinSkiles Catching Exception rileva gli errori di sintassi (e anche i segnali di interruzione). Dammi un buon scenario per farlo nel codice di produzione. Posso ricevere i segnali direttamente, ma dovresti farlo esplicitamente per chiarire che stai creando un gestore di segnali. Sto solo catturando l'eccezione ... cattiva, cattiva idea. Cattura anche le cose che non dovresti cercare di catturare.
RonLugge

6
Uno dei pochi casi comuni in cui esso è sano di mente in soccorso da eccezione è per scopi di registrazione / reporting, nel qual caso si dovrebbe immediatamente re-raise l'eccezione: stackoverflow.com/a/10048406/252346
aelesbao

198

Puoi anche definire un metodo 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

A seconda del tuo obiettivo, potresti anche considerare di NON gestire le eccezioni in base al controller. Invece, usa qualcosa come la gem exception_handler per gestire le risposte alle eccezioni in modo coerente. Come bonus, questo approccio gestirà anche le eccezioni che si verificano a livello del middleware, come l'analisi delle richieste o gli errori di connessione al database che l'applicazione non vede. Anche la gemma exception_notifier potrebbe essere di interesse.


4
Questo è ancora più utile in quanto consente di catturare le eccezioni in modo SECCO.
m33lky

E se utilizzo rescue_from senza parametri? si comporterà come il salvataggio? rilevare tutti gli errori?
minohimself

2
Non è una cattiva pratica rescue_from Exception? La mia comprensione è che è meglio salvare da StandardError, quindi cose come SyntaxErrore LoadErrornon vengono catturate.
lobati

Sì, è una cattiva idea salvare "Eccezione". Vedere "Rubino eccezionale" di Avdi Grimm per i motivi per cui ciò può essere problematico.
Midwire

34

Puoi rilevare le eccezioni per tipo:

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
Attento a non salvare Exceptiondirettamente; vedi stackoverflow.com/questions/10048173/…
Thibaut Barrère

10

rescue senza argomenti salverà qualsiasi errore.

Quindi, vorrai:

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
Domanda obsoleta, ma questa risposta non è corretta. rescue senza argomenti gestisce solo StandardError robots
Keith Gaddis

0

In realtà, se vuoi davvero catturare tutto , devi solo creare la tua app per le eccezioni, che ti consente di personalizzare il comportamento che viene solitamente gestito dal middleware PublicExceptions: https://github.com/rails/rails/blob/4-2 -stable / actionpack / lib / action_dispatch / middleware / public_exceptions.rb

Un sacco di altre risposte condividono gemme che lo fanno per te, ma non c'è davvero alcun motivo per cui non puoi semplicemente guardarle e farlo da solo.

Un avvertimento: assicurati di non sollevare mai un'eccezione nel tuo gestore di eccezioni. Altrimenti ottieni un brutto FAILSAFE_RESPONSE https://github.com/rails/rails/blob/4-2-stable/actionpack/lib/action_dispatch/middleware/show_exceptions.rb#L4-L22

A proposito, il comportamento nel controller deriva da rescuable: https://github.com/rails/rails/blob/4-2-stable/activesupport/lib/active_support/rescuable.rb#L32-L51

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.