Je définis une exception personnalisée sur un modèle dans les rails comme une sorte de wrapper Exception: ( begin[code]rescue[raise custom exception]end
)
Lorsque je soulève l’exception, j’aimerais lui transmettre quelques informations sur a) l’instance du modèle dont les fonctions internes génèrent l’erreur et b) l’erreur interceptée.
Cela se passe sur une méthode d’importation automatisée d’un modèle qui est alimenté par une requête POST à partir d’une source de données étrangère.
tldr; Comment peut-on transmettre des arguments à une exception, étant donné que vous définissez vous-même l’exception? J’ai une méthode d’initialisation sur cette exception, mais la syntaxe raise
semble accepter uniquement une classe et un message Exception, aucun paramètre facultatif transmis au processus d’instanciation.
créer une instance de votre exception avec new:
class CustomException < StandardError def initialize(data) @data = data end end # => nil raise CustomException.new(bla: "blupp") # CustomException: CustomException
class FooError < StandardError attr_reader :foo def initialize(foo) super @foo = foo end end
C'est le meilleur moyen si vous suivez le Guide de style Rubocop et transmettez toujours votre message comme deuxième argument à raise
:
raise FooError.new('the foo'), 'bar baz'
Vous pouvez obtenir comme ça:
rescue FooError => error error.foo # => 'the foo' error.message # => 'bar baz'
Si vous voulez définir le message d'erreur dans FooError
alors écrivez:
class FooError < StandardError attr_reader :foo def initialize(foo) super @foo = foo end def message "The foo is: #{foo}" end end
raise
Comme le dit le Guide de style Rubocop , le message et la classe d’exception doivent être fournis sous forme d’arguments séparés, car si vous écrivez:
raise FooError.new('bar baz')
Et si vous voulez passer un backtrace à raise
, il n'y a aucun moyen de le faire sans passer le message deux fois:
raise FooError.new('bar baz'), 'bar baz', other_error.backtrace
Comme le dit cette réponse , vous devrez transmettre une trace en arrière si vous souhaitez relancer une exception en tant que nouvelle instance avec le même chemin de retour et un message ou des données différents.
initialize
, appelez super
, pas super(message)
Voici trois manières différentes d'implémenter FooError
avec un code de test que vous pouvez exécuter dans Pry:
class SuperError < StandardError attr_reader :foo def initialize(foo) super @foo = foo end end class SuperWithMessageError < StandardError attr_reader :foo def initialize(foo) super(message) @foo = foo end end class SuperWithMessageArgumentError < StandardError attr_reader :foo def initialize(message = nil, foo) super(message) @foo = foo end end # All three classes behave the same except in this case: raise SuperError, 'bar' _ex_.foo # => 'bar' _ex_.message # => 'bar' raise SuperWithMessageError, 'bar' _ex_.foo # => 'bar' _ex_.message # => 'SuperWithMessageError' raise SuperWithMessageArgumentError, 'bar' _ex_.foo # => 'bar' _ex_.message # => 'SuperWithMessageArgumentError'
Dans SuperWithMessageError
et SuperWithMessageArgumentError
le message n'est pas défini correctement. SuperError
est donc l'implémentation correcte.
Voici un exemple de code ajoutant un code à une erreur:
class MyCustomError < StandardError attr_reader :code def initialize(code) @code = code end def to_s "[#{code}] #{super}" end end
Et pour le soulever: raise MyCustomError.new(code), message
Vous pouvez créer une nouvelle instance de votre sous-classe Exception
, puis augmentez-la. Par exemple:
begin # do something rescue => e error = MyException.new(e, 'some info') raise error end