Skip to main content

Ruby on Rails Part 4 - Exception Handling

  Ruby on Rails Part 4 - Exception Handling 

Table of content

  1. Exception Handling

  2. retry

  3. raise

  4. ensure

  5. else 

  6. catch and throw

  7. Exception classes

Exception Handling

Enclose the code that could raise an exception with a begin/end block and use rescue clauses to tell Ruby the types of exceptions that you want to handle. The syntax for exception handling :

begin 

    #- statements


rescue OneTypeOfException 

    #-
 handle the exception

rescue AnotherTypeOfException 

    #- 
handle the exception

else 

    
# Other exceptions


ensure 


    # ensure block is always executed


end 


Everything from begin to rescue is protected 

in the block.


If an exception occurs during the execution of this block of code, control is passed to the 

block between rescue and end.



For each rescue clause in the begin block, Ruby compares the raised Exception against each 

of the parameters of the rescue block one by one.


The correct match is the exception named in the rescue clause is the same as the type 

of the currently thrown exception, or is a superclass of that exception.

In an event that an exception does not match any of the error types specified, it uses the else clause after all the rescue clauses.

 
begin
i = 5/0
rescue
puts "Division by zero not allowed"
end
 

Output

 
$ ruby exception_handling.rb
Division by zero not allowed
 

retry

You can capture an exception using rescue block and then use retry statement to execute begin block from the beginning.The retry is illustrated as below.

 
begin
# Exceptions raised by the code here
# and be caught by the following rescue clause
rescue
# This block captures all types of exceptions
retry # Thr retry moves control to the beginning of begin
end 
 

In the below code, following is the flow of process: An exception occurred at opening of the file due to non_existent_file name, rescue captures the exception. In the rescue the fname was re-assigned to a existing_file name. With retry the control goes to the start of the begin block. This time file opens successfully and continues with the code flow. 

If the retry statement also raises an exception then this will trigger an infinite loop. So be careful while using retry command. 

 
fname = '/non_existent_file'
begin
file = open(fname)
if file
  puts "File opened successfully"
end
rescue
fname = "existing_file"
retry
end
 

raise

Raise statement is used to raise/throw an exception. This is similar to the ‘throws’ keyword in Java. The statement has multiple forms.

raise    # this raises a generic runtime error


OR 


raise "Error Message"
  # this raises a generic runtime error with a custom message

OR


raise ExceptionType, "Error Message"
 # this raises an exception with a custom message

OR


raise ExceptionType, "Error Message" condition 
 # raises an exception with a custom message if the condition is true else raise no exception 


The first form simply re-raises the current exception (or a RuntimeError if there is no current exception). This is used in exception handlers that need to intercept an exception before passing it on. 



The second form creates a new RuntimeError exception, setting its message to the given string. This exception is then raised up the call stack. 



The third form uses the first argument to create an exception and then sets the associated message to the second argument.

The fourth form is similar to the third form but you can add any conditional statement like unless to raise an exception. If the condition is true then raise the exception. 

 
begin
puts 'Before raise.'
raise 'Raising an error'
puts 'After raise'
rescue Exception => e
puts 'In rescue block'
puts e.class
end
puts 'Outside of begin block'

Output

 
$ ruby raise_exception_example.rb
Before raise.
In rescue block
RuntimeError
Outside of begin block
 
 
Raise with custom message
 
 
begin
raise 'A test exception'
rescue Exception => e
puts e.message
puts e.backtrace
end 
 

Output

 
$ ruby raise_custom_message.rb
A test exception
a.rb:2:in `<main>'
$
 

ensure

Sometimes, you need to guarantee that some processing is done at the end of a block of code, regardless of whether an exception was raised. This is similar to the finally block in java. The syntax for ensure :

                                        begin

                                             #.. process

                                            #.. raise exception 
                                        rescue
                                            #.. handle error
                                        ensure
                                            #.. finally ensure execution
                                            #.. This block always executes
                                        end
 
 
begin
raise 'A test exception.'
rescue Exception => e
puts e.message
puts e.backtrace.inspect
ensure
puts "Ensuring execution"
end 
 
 
Output
 
$ ruby a.rb
A test exception.
["a.rb:2:in `<main>'"]
Ensuring execution
$
 

else

If the else clause is present, it goes after the rescue clauses and before any ensure. The body of an else clause is executed only if no exceptions are raised by the main body of code.


# Syntax of else in exception handling

begin

    #.. process

    #.. raise exception

rescue

    #.. handle error

else

    #.. executes if there is no exception

ensure

    #.. finally ensure execution

    #.. This will always execute

end

Example of else block.

 
begin
puts "I'm not raising exception"
rescue Exception => e
puts e.message
puts e.backtrace.inspect
else
puts "Congratulations-- no errors!"
ensure
puts "Ensuring execution"
end 
 

Output

 
$ ruby else_block_example.rb
I'm not raising exception
Congratulations-- no errors!
Ensuring execution
 

catch and throw

throw: Throws the control to a catch block with the same label
. 

catch: Catches the control thrown by a throw command with same label.

catch and throw are mainly used to jump of out multiple nested constructs. break can only break out of a single loop at once, but throw can break out of all the loops.

Syntax of throw and catch :

catch :label_name do


# matching catch will be executed when the throw block is encountered

throw :label_name condition 

# thrown only if the condition is true # this block will not be executed

end

Example of catch - throw :


 
flag = 0
catch :labelName do
puts("This will not be executed") if flag == 1
for i in 0..100000
for j in 0..100000
for k in 0..100000
for l in 0..100000
for m in 0..100000
for n in 0..100000
for o in 0..100000
for p in 0..100000
flag = 1
throw :labelName if p == 0
puts "This statement and everything below will not be executed"
end
end
end
end
end
end
end
end
end
puts("This will be executed") if flag == 1 
 


Output

 
$ ruby catch_throw_example.rb
This will be executed
$
 

Exception classes

The Exception class is the parent of all exception classes. It can hold all other exceptions. The other main types of exception classes are as follows:

Interrupt


NoMemoryError

SignalException

ScriptError


StandardError

SystemExit

All these classes are the subclasses of the parent Exception class. We can create our own exception classes, but they need to be subclass of either class Exception or one of its descendants.

Create my own exception class by inheriting from the Exception class :

 
class MyCustomException < Exception
attr_reader :reason
def initialize(reason)
@reason = reason
end
end

begin
# Exception raised in the following line
5/0
rescue
# The exception was raised to a higher level using the raise keyword
raise MyCustomException.new("Divide by 0").reason
end 
 

Output

 
$ ruby custom_exception_class.rb
custom_exception_class.rb:13:in `rescue in <main>': Divide by 0 (RuntimeError)
from custom_exception_class.rb:8:in `<main>'
$
 

Thank you folks, if you like my post do check my other posts on Django with Python 3 and Ruby on Rails  on SWE crunch

 

Most viewed

Ruby on rails part 6 - Blocks , lambda, procs and closure

 Blocks , lambda, procs  and closure Table of content  1. Blocks 2. Lambda 3. Procs 4. Closure Blocks  Ruby blocks are little anonymous functions that can be passed into methods. Blocks are enclosed in a do-end statement or between brackets {} 
. Blocks can have multiple arguments
. The argument names are defined between two pipe | characters. Blocks are typically used with ‘each’ method which iterates over a list. Syntax of block using {} ['List of items'].each { | block arguments|  block body }  Syntax of block using do-end ['List of items'].each do | block arguments |      # block body end Example of block declared as do-end with each method.   [ 1 , 2 , 3 ].each do |num| puts num end     Output   $ ruby block_with_each.rb 1 2 3 $    Blocks can also be saved in variables or passed as argument to another function.   yield is a Ruby keyword that is used to call a block. When you use the yield keyword, the code inside the block will run. Example of saving a bl