Handling Exceptions in Ruby
Handling Exceptions in Ruby is Easy!
Exceptions are Ruby’s way of allowing us to attempt to recover from errors. The basic syntax for handling exceptions in Ruby goes something like this:
begin
do_something_risky
rescue
recover_from_exception
end
We can gather more information from an exception like so:
begin
do_something_risky
rescue StandardError => e
puts e.message
end
Notice we rescued StandardError and not Exception. There are many types of exception you might not necessarily want to rescue. For example, pressing CTRL+C or sending SIGTERM to the process would not work as expected and you might have to resort to SIGKILL.
Implicit Contexts
It’s not always necessary to explicitly type begin. Class, module, and method definitions and ruby blocks serve as implicit rescue contexts.
def safe_method
do_something_risky
rescue StandardError => e
logger.error e.message
logger.debug e.backtrace.join("\n")
end
Rescuing exceptions is a good use case for a logger.
Multiple Exception Handling
You can handle multiple types of exception differently. Just be sure to put specific exception types before StandardError if rescue it.
begin
do_something_risky
rescue WhizBangError => e
handle_specific e
rescue StandardError => e
handle_generic e
end
Re-raising Exceptions
You can re-raise an exception after doing something with it. raise knows to re-raise the exception in the rescue context.
begin
do_something_risky
rescue StandardError => e
logger.error e.message
raise
end
Retrying
You can retry the error-prone task after rescuing.
def safe_method
retried = false
begin
do_something_risky
rescue NotLoggedInError
log_in
unless retried
retried = true
retry
end
end
end
Just be sure to check whether you’ve already retried first to avoid an endless loop if the fix doesn’t work.
Cleaning Up
In some situations there’s code that needs to run whether there’s an exception or not. The most common example is closing a file handle
begin
file = File.open 'file', 'w'
write_to_file file
rescue
handle_file_error
ensure
file.close unless file.nil?
end
Defining Your Own Exceptions
class BarlessFooError < StandardError
end
Failing
fail BarlessFooError, ‘Foo requires a bar.’ if foo.bar.nil?
Use fail rather than raise to surface an exception unless you are reraising as above.