Comment puis-je lever une exception dans Rails pour qu'elle se comporte comme les autres exceptions Rails?

91

Je voudrais soulever une exception pour qu'elle fasse la même chose qu'une exception Rails normale. En particulier, affichez l'exception et la trace de la pile en mode développement et affichez la page "Nous sommes désolés, mais quelque chose s'est mal passé" en mode production.

J'ai essayé ce qui suit:

raise "safety_care group missing!" if group.nil?

Mais il écrit simplement "ERROR signing up, group missing!"dans le fichier development.log

Chirag Patel
la source
2
le message d'erreur que vous avez publié ne semble pas provenir de cette exception (c'est un message différent) est-ce vraiment ce que vous voyez?
levinalex

Réponses:

139

Vous n'avez rien à faire de spécial, cela devrait simplement fonctionner.

Quand j'ai une nouvelle application de rails avec ce contrôleur:

class FooController < ApplicationController
  def index
    raise "error"
  end
end

et allez à http://127.0.0.1:3000/foo/

Je vois l'exception avec une trace de pile.

Il se peut que vous ne voyiez pas l'intégralité de la trace de pile dans le journal de la console car Rails (depuis 2.3) filtre les lignes de la trace de pile qui proviennent du framework lui-même.

Voir config/initializers/backtrace_silencers.rbdans votre projet Rails

levinalex
la source
2
Excellente réponse concise.
rcd
1
Le lien skitch (voir l'exception avec une trace de pile) ne fonctionne plus
Asaf
@levinalex sera-t-il sûr en mode production pour afficher le stacktrace?
BKSpurgeon
@levinalex - merci Alex. existe-t-il un moyen d'ajouter une chaîne personnalisée au message d'erreur?
BKSpurgeon
62

Vous pouvez le faire comme ceci:

class UsersController < ApplicationController
  ## Exception Handling
  class NotActivated < StandardError
  end

  rescue_from NotActivated, :with => :not_activated

  def not_activated(exception)
    flash[:notice] = "This user is not activated."
    Event.new_event "Exception: #{exception.message}", current_user, request.remote_ip
    redirect_to "/"
  end

  def show
      // Do something that fails..
      raise NotActivated unless @user.is_activated?
  end
end

Ce que vous faites ici est de créer une classe "NotActivated" qui servira d'exception. En utilisant lever, vous pouvez lancer "NotActivated" comme exception. rescue_from est le moyen d'intercepter une exception avec une méthode spécifiée (not_activated dans ce cas). Un très long exemple, mais il devrait vous montrer comment cela fonctionne.

Meilleurs voeux,
Fabian

Halfdan
la source
Cela n'affiche pas l'exception et la trace de pile en mode développement et affiche la page "Nous sommes désolés, mais quelque chose s'est mal passé" en mode production.
Chirag Patel
2
La page "Nous sommes désolés" est en fait le gestionnaire d'erreurs 500 de votre serveur Web. Vérifiez votre fichier .htaccess et vous le verrez généralement là
Jeff Paquette
Peut-être pas une réponse au PO mais un exemple très utile, merci!
Neil Stockbridge
11

Si vous avez besoin d'un moyen plus simple de le faire et que vous ne voulez pas trop de bruit, une exécution simple pourrait être:

raise Exception.new('something bad happened!')

Cela soulèvera une exception, disons eavece.message = something bad happened!

et puis vous pouvez le sauver pendant que vous sauvez toutes les autres exceptions en général.

Sambhav Sharma
la source
Ce n'est pas une bonne idée de lever ou de sauver 'Exception' lui-même, essayez d'utiliser StandardError à la place. Voir ceci pour plus de détails: stackoverflow.com/questions/10048173/…
Ekamjit Singh