Gérer les erreurs en Ruby : comprendre, déboguer, ne plus paniquer
Enregistrer
•Temps de lecture: 8 min•Vues: 28Niveau:Intermédiaire à Confirmé
environ 1 moispar Franci-lobbie LALANE(Modifié)
Tags:
#rails
#ruby
#exceptions
#erreurs
#goodpractices
“There are two ways to write error-free programs; only the third one works.” — Alan J. Perlis
Introduction ⚙️
Quand on code en Ruby, on finit toujours par croiser des erreurs. Pas parce qu'on est mauvais, mais parce que le code qu'on écrit est vivant, souvent complexe, et parfois un peu capricieux. Et heureusement : les erreurs sont nos meilleurs signaux pour corriger, améliorer et comprendre notre code.
Ce guide est là pour t'apprendre à apprivoiser les exceptions Ruby :
Comment elles fonctionnent ?
Quelles sont les plus courantes ?
Comment les lire intelligemment ?
Comment les gérer proprement ?
Comment créer ses propres erreurs utiles pour ton app ?
Avec des exemples concrets, des bonnes pratiques, des nouveautés de Ruby 3.4.1, et même quelques retours de devs glanés sur Reddit. Bref, tout ce qu’il faut pour que les erreurs ne te fassent plus peur.
I. C’est quoi une exception en Ruby ? 🧩
Une exception est une situation anormale qui interrompt l’exécution normale d’un programme. Par exemple : diviser par zéro, appeler une méthode qui n'existe pas, ouvrir un fichier absent…
Ruby utilise des objets pour représenter ces erreurs. Chaque type d'erreur est une classe, souvent héritée de StandardError.
Structure de base
begin
# code potentiellement problématique
rescue
# code exécuté en cas d’erreur
end
Quand une erreur est levée, Ruby saute immédiatement au bloc rescue correspondant. Si aucun bloc ne correspond, l’exception se propage dans la pile jusqu’à ce que quelque chose la capture… ou que le programme plante.
Il existe donc deux grands types d'erreurs :
Silencieuses : capturées et gérées
Fatales : non capturées, le programme s’arrête
II. Lire un message d’erreur : le stack trace expliqué 🐛
Un message d'erreur Ruby, aussi appelé stack trace, est ton meilleur ami. Il te dit exactement :
le fichier concerné
la ligne où ça a planté
le type d’erreur
le message explicite
Exemple :
main.rb:12:in `calculate': divided by 0 (ZeroDivisionError)
Tu sais que dans main.rb, à la ligne 12, dans la méthode calculate, un ZeroDivisionError a été levé avec le message "divided by 0".
Bonus sympa : Did you mean?
Depuis Ruby 2.3, Ruby te suggère souvent des corrections de nom :
NameError: undefined local variable or method `usr' for main:Object
Did you mean? user
Une petite pépite pour corriger les fautes de frappe 😄
III. Les erreurs les plus fréquentes 🧱
Voici les erreurs que tu rencontreras le plus souvent. Pour chaque type : une explication, un exemple, une astuce.
NameError
Variable ou constante non définie.
puts total_price
# => NameError: undefined local variable or method 'total_price'
Solution : vérifier la déclaration, la casse, ou la portée de ta variable.
NoMethodError
Méthode appelée sur un objet qui ne la connaît pas.
user = nil
user.name
# => NoMethodError: undefined method `name` for nil:NilClass
Solution : bien vérifier que ton objet n’est pas nil, ou utiliser &. (safe navigation operator).
ArgumentError
Le nombre ou type d’arguments ne colle pas.
def greet(name, age); end
greet("Alice")
# => ArgumentError: wrong number of arguments (given 1, expected 2)
Solution : toujours relire la signature de la méthode.
Solution : fermer toutes tes structures (end) et valider ton code dans un éditeur.
TypeError
Type d’objet inapproprié.
[1, 2, 3] + "salut"
# => TypeError: no implicit conversion of String into Array
Solution : toujours s'assurer que les objets sont compatibles.
ZeroDivisionError
La classique division par zéro 😬
10 / 0
# => ZeroDivisionError: divided by 0
Solution : toujours vérifier les dénominateurs avant de diviser.
LoadError / Errno::ENOENT / IOError
Fichier ou ressource manquante.
File.read("/path/to/missing/file")
# => Errno::ENOENT: No such file or directory
Solution : vérifier les chemins, les permissions, et tester leur existence avant appel.
IV. Comment gérer les erreurs proprement 🛠️
Ruby nous donne plusieurs outils pour intercepter, traiter, relancer ou ignorer les erreurs. Mais comme tout outil puissant, ça peut aussi mal tourner si c’est mal utilisé.
rescue avec variable
C’est la base : capturer l’exception dans une variable pour l’analyser.
begin
risky_code
rescue => e
puts e.class # Type d'erreur
puts e.message # Message associé
puts e.backtrace # Détail des appels
end
Tu peux ensuite logger, alerter, ou relancer l’erreur après traitement si besoin avec raise e.
else et ensure
else s’exécute si aucune erreur n’est levée
ensure s’exécute dans tous les cas, erreur ou pas
begin
puts "On tente un truc"
rescue => e
puts "Erreur capturée : #{e.message}"
else
puts "Tout s'est bien passé !"
ensure
puts "Nettoyage systématique"
end
C’est super utile pour fermer un fichier, libérer une ressource, ou logger une info de fin de traitement.
retry et raise
Tu peux parfois vouloir réessayer après une erreur ponctuelle (réseau, base de données, etc.). Ruby permet ça avec retry.
tries = 0
begin
fetch_remote_data
rescue NetworkTimeout => e
tries += 1
retry if tries < 3
raise "Échec après 3 tentatives"
end
Mais attention à ne pas créer de boucle infinie. Mets des limites claires.
V. Lever ses propres exceptions 🚨
Lever une exception, c’est dire « stop, cette situation est invalide, je préfère interrompre l’exécution ici ».
Avec raise simple
raise "Ce nom est invalide"
C’est pratique pour signaler un problème métier ou un cas limite mal géré.
Avec une classe d’exception personnalisée
class PermissionDenied < StandardError; end
def delete_user(user)
raise PermissionDenied, "Vous n'avez pas le droit de faire ça" unless user.admin?
end
Créer tes propres classes rend les erreurs plus explicites et facilite leur gestion (tu peux rescue PermissionDenied uniquement).
En ajoutant des attributs
class ApiError < StandardError
attr_reader :code
def initialize(message, code)
super(message)
@code = code
end
end
Tu peux ainsi accéder à plus d’infos quand tu traites l’erreur (e.code). Très utile pour les appels HTTP ou les erreurs de validation métier.
VI. L’arbre des exceptions Ruby 🌳
Ruby organise toutes ses erreurs en arbre. Tu peux en voir un extrait ici :
Pourquoi c’est important ? Parce que Ruby ne capture que StandardError par défaut.
Donc si tu fais rescue, ça ne prendra pas une SyntaxError ou un SystemExit. C’est voulu : ça évite de masquer les plantages critiques.
Moralité : hérite toujours de StandardError pour tes classes d’erreur perso.
VII. Nouveautés et changements dans Ruby 3.4.1 🧪
La gestion des exceptions a évolué avec les versions récentes.
full_message
Depuis Ruby 2.6, tu peux utiliser e.full_message pour une sortie lisible et colorée :
rescue => e
puts e.full_message(highlight: true)
Pratique pour le debug sans avoir à parser backtrace manuellement.
cause
Si tu relèves une erreur dans un rescue, Ruby garde une trace de l’originale :
begin
raise "Erreur A"
rescue => e
raise "Erreur B"
end
e.cause permet de suivre la chaîne d’erreurs. Top pour les logs ou les outils d’observabilité.
Améliorations internes
Ruby 3.4 a aussi clarifié les messages dans les lambdas, les blocs, et les appels indirects. Tu devrais voir moins de "undefined method" bizarres et plus d’infos utiles.
VIII. Bonnes pratiques ✅
Voici quelques règles simples pour éviter les pièges les plus courants :
Ne fais jamais rescue nil : tu masques l’erreur, tu ne la règles pas.
Ne rescue pas Exception sauf cas ultra spécifiques (comme un moteur de sandbox).
Loggue toujours ce que tu interceptes (au moins e.message).
Utilise ensure pour nettoyer après une opération critique (fichier, DB, etc.).
Crée des erreurs personnalisées avec des noms clairs : InvalidCredentials, RateLimitExceeded, etc.
Ces petites habitudes font une énorme différence dans la stabilité et la lisibilité de ton code.
IX. Bonus : outils de debug Ruby 🧰
Quelques pépites pour t'aider à mieux comprendre et corriger tes erreurs Ruby :
pry-rescue : ouvre un REPL automatiquement dès qu'une exception se produit.
byebug : très utile pour mettre un breakpoint dans un rescue.
binding.irb ou binding.pry : explore l'état du programme en live.
exception.full_message(highlight: true) : affiche le message d’erreur avec couleurs et contexte.
Sentry / Rollbar / Bugsnag : pour suivre les exceptions en production.
Conclusion 🎬
Les erreurs Ruby ne sont pas là pour t'embêter. Elles sont là pour te parler.
Apprendre à les lire, les comprendre et les utiliser fait de toi un meilleur développeur. Et Ruby a l’avantage de rendre ce processus vraiment agréable, comparé à d’autres langages plus obscurs.
Prends le temps d’écouter ce que l’exception essaie de te dire.
Et surtout, continue à casser ton code. C’est comme ça qu’on apprend.