Reraise (Same Exception) After Catching an Exception in Ruby

Reraise (same exception) after catching an exception in Ruby

Sometimes we just want to know an error happened, without having to actually handle the error.

It is often the case that the one responsible for handling errors is user of the object: the caller. What if we are interested in the error, but don't want to assume that responsibility? We rescue the error, do whatever we need to do and then propagate the signal up the stack as if nothing had happened.

For example, what if we wanted to log the error message and then let the caller deal with it?

begin
this_will_fail!
rescue Failure => error
log.error error.message
raise
end

Calling raise without any arguments will raise the last error. In our case, we are re-raising error.

In the example you presented in your question, re-raising the error is simply not necessary. You could simply let it propagate up the stack naturally. The only difference in your example is you're creating a new error object and raising it instead of re-raising the last one.

How can I re-raise a Ruby exception in a Rails rescue_from statement?

Apparently raising exceptions in a rescue_from is a bad idea and according to the Rails docs, exceptions raised in a handler are not bubbled up:

Exceptions raised inside exception handlers are not propagated up.

Docs: http://api.rubyonrails.org/classes/ActiveSupport/Rescuable/ClassMethods.html

Instead of re-raising RocketPants' exception, I'm simply creating and returning the JSON error message myself:

  def user_not_authorized
# error! :forbidden
head 403
error = { error: 'Action not allowed.', error_description: 'Sorry, you are not allowed to perform this action.'}
expose error
end

This works!

UPDATE

I've since found an even cleaner solution: just map the Pundit exception to the RocketPants exception. This means that whenever a Pundit::NotAuthorizedError error is raised it'll be treated as a RocketPants::Forbidden error.

Got the entire solution down to a single line of code at the top of base_controller.rb:

  map_error! Pundit::NotAuthorizedError, RocketPants::Forbidden

No handler required.

ruby - re-raise exception with sub-exception

Take a look at the tricks from the talk Exceptional Ruby by Avdi Grimm:

class MyError < StandardError
attr_reader :original
def initialize(msg, original=nil);
super(msg);
@original = original;
end
end
# ...
rescue => error
raise MyError.new("Error B", error)
end

How do I prevent two exception stacks when catching and re-raising Ruby exceptions?

The "second" (original) exception is the cause of the rescued exception which is references by your new exception as it is created with Exception#exception.

Starting with Ruby 3.1, irb prints the details of the cause in addition to the actual exception to aid in debugging. Previous Ruby versions have ignored the cause here.

Thus, you can use other means to handle your exceptions rather than using Ruby's default handler of printing the details of an otherwise unhandled exception, e.g. by adding an explicit exception handler. Alternatively, you can also explicitly set the cause as you are creating your new exception:

begin
puts 12 / 0
rescue ZeroDivisionError => e
raise e.class, "new message #{e.message}", cause: nil
end

Preserve a variable after exception is raised

This is an abuse of exceptions, IMO, because this is not an exceptional case. Instead, consider simply logging something:

    if c =~ /[a-zA-Z0-9_]/
warn "Identifer was too long and was truncated"
this_id += c

If you must use the exception for some reason, then the most straightforward way is just to put this_id in an instance variable instead:

@this_identifier = id
# ...

Then, when you break in the rescue, just have the last expression be @this_identifier to return that value (yuck).


Bonus comment: this is a truly wretched way to parse source files. You should be using something like RubyParser if you're parsing Ruby, or Treetop if you're parsing something else.



Related Topics



Leave a reply



Submit