171 votes

Où définir des types d'erreurs personnalisés dans Ruby et/ou Rails ?

Existe-t-il une meilleure pratique pour définir des types d'erreurs personnalisés dans une bibliothèque Ruby (gem) ou une application Ruby on Rails ? Plus précisément :

  1. Quelle est leur place structurelle dans le projet ? Dans un fichier séparé, en ligne avec la définition du module/de la classe concerné(e), quelque part ailleurs ?
  2. Existe-t-il des conventions qui établissent quand à et quand ne pas créer un nouveau type d'erreur ?

Les bibliothèques ont des façons de faire différentes, et je n'ai pas remarqué de véritables modèles. Certaines bibliothèques utilisent toujours des types d'erreurs personnalisés tandis que d'autres ne les utilisent pas du tout ; certaines ont toutes les erreurs qui étendent StandardError tandis que d'autres ont des hiérarchies imbriquées ; certaines sont juste des définitions de classes vides, d'autres ont toutes sortes d'astuces astucieuses.

Oh, et juste parce que j'ai l'impression que les appeler "types d'erreurs" est un peu ambigu, ce que je veux dire c'est ceci :

class AuthenticationError < StandardError; end
class InvalidUsername < AuthenticationError; end

237voto

Mike Lewis Points 29305

Pour les pierres précieuses

J'ai vu à plusieurs reprises que vous définissiez les exceptions de cette manière :

gem_dir/lib/gem_name/exceptions.rb

et défini comme suit :

module GemName

  class AuthenticationError < StandardError; end
  class InvalidUsername < AuthenticationError; end

end

Un exemple de ceci serait quelque chose comme ceci dans httparty

Pour Ruby on Rails

Placez-les dans votre dossier lib/ sous un fichier appelé exceptions.rb, qui ressemblerait à ceci :

module Exceptions
  class AuthenticationError < StandardError; end
  class InvalidUsername < AuthenticationError; end
end

et vous l'utiliserez comme suit :

raise Exceptions::InvalidUsername

0 votes

Pour les gemmes, il semble qu'il faille également inclure le fichier d'exception. Voir cet exemple, toujours à partir de httparty : github.com/jnunemaker/httparty/blob/

48 votes

Pourquoi les placer dans l'espace de noms Exceptions module ?

22 votes

Je pense que /lib n'est peut-être pas l'endroit idéal pour les erreurs. Elles sont très spécifiques à l'application et j'ai l'impression que le code que je mets dans /lib est un code qui peut être réutilisé dans d'autres applications.

32voto

PETER Points 534

Dans les rails, vous pouvez faire app/errors répertoire

# app/errors/foo_error.rb
class FooError < StandardError; end

redémarrer spring/server et il devrait le récupérer

27voto

Dean Radcliffe Points 694

Je pense que pour avoir des fichiers sources cohérents dans votre projet, vous devriez définir les erreurs dans la classe dans laquelle elles peuvent être lancées et nulle part ailleurs.

Une certaine hiérarchie peut être utile - les espaces de noms permettent d'éviter les chaînes redondantes dans les noms de types - mais c'est plus une question de goût - il n'est pas nécessaire d'aller trop loin si vous avez au moins un type d'exception personnalisé dans votre application que vous utilisez tout au long pour différencier les cas d'exception "intentionnels" des cas d'exception "accidentels".

11 votes

Bien qu'en théorie vous ayez raison, que se passe-t-il lorsque la même erreur peut être soulevée par différentes classes dans des situations totalement différentes ?

1 votes

@Alain Pourquoi ne pas définir les erreurs utilisées par plusieurs classes dans un module Exceptions/Erreurs, mais laisser toutes les autres définies dans la seule classe qui les utilise ?

0 votes

@ScottW, Dans ce cas, nous comptons sur le développeur pour qu'il se souvienne de vérifier.

20voto

Matt Points 34

C'est une vieille question, mais je voulais partager la façon dont je gère les erreurs personnalisées dans Rails, y compris l'attachement des messages d'erreur, les tests, et la façon de gérer cela avec ActiveRecord modèles.

Création d'une erreur personnalisée

class MyClass
  # create a custome error
  class MissingRequirement < StandardError; end

  def my_instance_method
    raise MyClass::MissingRequirement, "My error msg" unless true   
  end
end

Test (minitest)

test "should raise MissingRequirement if ____ is missing"
  # should raise an error
  error = assert_raises(MyClass::MissingRequirement) {
    MyClass.new.my_instance_method
  }

  assert error.message = "My error msg"
end

Avec ActiveRecord

Je pense qu'il est utile de noter que si l'on travaille avec un ActiveRecord un modèle populaire consiste à ajouter une erreur au modèle, comme décrit ci-dessous, afin que vos validations échouent :

def MyModel < ActiveRecord::Base
  validate :code_does_not_contain_hyphens

  def code_does_not_contain_hyphens
    errors.add(:code, "cannot contain hyphens") if code.include?("-")
  end
end

Lors de l'exécution des validations, cette méthode s'appuiera sur la méthode ActiveRecord ActiveRecord::RecordInvalid et fera échouer les validations.

J'espère que cela vous aidera !

12voto

spyle Points 413

Pour s'assurer que l'autoloading fonctionne comme prévu dans Rails 4.1.10 pour plusieurs classes d'erreurs personnalisées, vous devrez spécifier des fichiers distincts pour chacune d'entre elles. Cela devrait fonctionner en développement avec son rechargement dynamique.

C'est ainsi que j'ai configuré les erreurs dans un projet récent :

En lib/app_name/error/base.rb

module AppName
    module Error
        class Base < StandardError; end
    end
end

et dans les erreurs personnalisées ultérieures, comme dans lib/app_name/error/bad_stuff.rb

module AppName
    module Error
        class BadStuff < ::AppName::Error::Base; end
    end
end

Vous devriez alors être en mesure d'appeler vos erreurs via :

 raise AppName::Error::BadStuff.new("Bad stuff just happened")

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X