Custom error handling in ruby


Created by Stan on 08-04-2023


Error handling is a crucial aspect of building robust and maintainable software. In Ruby, errors are raised in the form of exceptions, which can be caught and handled using begin, rescue, and ensure blocks. While Ruby provides a comprehensive set of built-in exceptions, sometimes you may need to create your own custom exceptions to better represent the specific errors that your application might encounter. In this article, we will discuss how to create and use custom exceptions in Ruby, along with practical code samples.

Creating custom exceptions

Creating a custom exception in Ruby is as simple as defining a new class that inherits from the StandardError class or one of its subclasses. Here's an example:

class AuthenticationError < StandardError
end

class AuthorizationError < StandardError
end

In this example, we create two custom exceptions: AuthenticationError and AuthorizationError. Both inherit from StandardError, the superclass for most built-in Ruby exceptions.

Raising custom exceptions

def authenticate(user, password)
  if user.nil? || user.password != password
    raise AuthenticationError, "Invalid username or password"
  end
end

def authorize(user, action)
  unless user.can_perform?(action)
    raise AuthorizationError, "User is not authorized to perform this action"
  end
end

In this example, we define two methods: authenticate and authorize. The authenticate method raises an AuthenticationError if the provided user is nil or the password is incorrect. The authorize method raises an AuthorizationError if the user is not authorized to perform the given action.

Handling custom exceptions

To handle custom exceptions, you can use begin, rescue, and ensure blocks just like you would with built-in exceptions. Here's an example:

class AuthErrorHandler
  def initialize
    @log_file = nil
  end

  def authenticate_and_authorize
    begin
      open_log_file
      user = find_user("john.doe")
      authenticate(user, "incorrect_password")
      authorize(user, "delete_account")
    rescue AuthenticationError => e
      log_error "Authentication error: #{e.message}"
    rescue AuthorizationError => e
      log_error "Authorization error: #{e.message}"
    ensure
      cleanup_resources
    end
  end

  def open_log_file
    @log_file = File.open("authentication.log", "a")
  end

  def log_error(message)
    @log_file.puts(message) if @log_file
  end

  def cleanup_resources
    @log_file.close if @log_file
  end

  # Other methods like authenticate, authorize, and find_user would be defined here
end

error_handler = AuthErrorHandler.new
error_handler.authenticate_and_authorize

In this example, we create a AuthErrorHandler class that handles the authentication and authorization process. The authenticate_and_authorize method contains the begin, rescue, and ensure blocks for handling exceptions. The cleanup_resources method is responsible for closing the log file, which is an instance variable @log_file. The cleanup_resources method is called in the ensure block, ensuring that the log file is closed regardless of whether an exception occurs during the authentication and authorization process.

By implementing cleanup_resources in this way, we can gracefully handle exceptions and ensure that the resources (in this case, the log file) are properly released, preventing resource leaks or other issues.

Adding custom behavior to exceptions

Sometimes you may want to add custom behavior or attributes to your exceptions. You can do this by defining methods and instance variables in your custom exception classes. Here's an example:

class ApiError < StandardError
  attr_reader :status_code

  def initialize(message, status_code)
    super(message)
    @status_code = status_code
  end
end

In this example, we create a custom ApiError exception that has an additional status_code attribute. The constructor (initialize method) takes a message and a status code as arguments and initializes the exception object accordingly.

Creating and using custom exceptions in Ruby is a powerful way to make your error handling more meaningful and expressive. By defining your own exceptions that represent specific errors your application might encounter, you can improve the readability and maintainability of your code. Furthermore, you can add custom behavior



Related Posts