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
Is Every Relavant Calculation Performed Every Time the Page Is Loaded
Replacing Text in One CSV Column Using Fastercsv
How to Export Environment Variable Permanently Using Ruby
How to Ruby on Rails Authentication with Ldap
How to Use Ruby for Shell Scripting
Rmagick Installation: Can't Find Magickwand.H
Checking If a Variable Is Not Nil and Not Zero in Ruby
Ruby Array to String Conversion
Link_To Method and Click Event in Rails
Ruby: How to Load a File into Interactive Ruby Console (Irb)
Remove Substring from the String
Rspec Allow/Expect VS Just Expect/And_Return
Error Installing Debugger-Linecache in Ruby 1.9.3
Good Cucumber Examples in the Wild
Strip Signatures and Replies from Emails