Last updated on June 30th, 2024 at 03:06 pm
Table of Contents
Catching Errors
Any program will potentially run into situations where the code has to say it found an error that it cannot gracefully recover from. This is known as Exception Handling. Exception Handling is implemented in the core of Ruby and exceptions will be raised any time you write code that has syntax errors or performs an illegal operation.
As a programmer you can not only catch and recover from these exceptions, you can also throw exceptions yourself.
The primary tool for capturing exceptions is the rescue
statement. If you implement the rescue
statement without any arguments, it will capture any and all exceptions that come its way.
def my_method
12 / 0 # This will throw a divide by zero error
rescue
puts "We got an error"
end
Usually, however, at the very least you want to be able to inform the user a little more precisely about the problem experienced and you can issue the raise
statement with a variable that will take on the value of the error.
def my_method
12 / 0 # This will throw a divide by zero error
rescue => err
puts "We got the error : #{err.message}"
end
Often, we will know what potential errors can occur and then be able to recover from them. In this case, we can specify which errors we can handle and which we have to pass on.
def my_method
12 / "zero" # This will throw an TypeError
rescue ZeroDivisionError => err
puts "We got the error : #{err.message}"
rescue => err
puts "We got some other error : #{err.message}"
end
It is also not uncommon to see explicit rescue blocks within methods, such as with the following.
def my_method
puts 'We have entered my method'
begin
12 / "zero"
rescue => err
puts "We got the error : #{err.message} "
end
puts 'execution in the method continues, even after a rescue'
end
You may notice that we didn’t have to put a return
or any other control statement after the first rescue
statement. Because the rescue
command is always at the end of the block, Ruby simply terminates execution of the block after the rescue is executed.
Sharing Rescue Code
There could be situations where you would have identical rescue methods in a given file. The rescue_from
command has been created to facilitate this. In the example code below, once the rescue_from has been defined, any method that raises the appropriate error will be handled by the defined method.
class MyController < ApplicationController
rescue_from SpecificExceptionClass, with: :handle_specific_exception
private
def handle_specific_exception(exception)
# handling code
end
end
Trying Again
Ruby allows you to try again if you think you can recover from an Exception. With the retry statement, execution restarts at the most recently preceding begin statement.
def my_method
numerator = 12
denominator = 0
begin
mistake = numerator / denominator
puts "The value is #{mistake}"
rescue => err
puts "We got the error : #{err.message}"
denominator = 1
retry
end
end
Throwing Errors
The raise
statement can be used to throw an exception. If you don’t specify the type of the error, Ruby will throw a RuntimeError.
def my_method
if something_bad_happened
raise "I can't take this any more…"
end
end
It it helpful to specify the type of error when you throw it so that layers above you might know what to catch.
def my_method
if something_bad_happened
raise ArgumentError, "I am in a bad mood and feel like arguing…"
end
end
You can also define your own error classes.
class MyError < StandardError
end
raise MyError, "My error message"