DEV Community

rossonevan
rossonevan

Posted on • Updated on

Generate more detailed errors in controllers using 'rescue_from' in Ruby on Rails

The most important parts of a web page application is returning information to the user while providing errors in order for a better understanding of why a problem is occurring when a user is interacting throughout the app. Through the application controllers, CRUD(Create, Read, Update, Destroy) methods are developed in order for the front-end to interact with the database created in the back-end.

.find vs .find_by

When creating the create, show, and update routes, the id of the data being displayed must be found. If the id cannot be found, an error will occur. For example, lets say we have a show methods in a movie controller:

class MoviesController < ApplicationController
  def show
    movie = Movie.find_by(id: params[:id])
    if movie
      render json: movie, status: :ok
    else
      render json: {error: "Movie not found"}, status: :not_found
    end
  end
 end
Enter fullscreen mode Exit fullscreen mode

By using .find_by, the return value is nil if the movie cannot be found. Therefore, an if/else statement needs to be formulated in order to generate an error that will be used to display to the user.

We can also use a rescue that ruby provides that can take the exception and use it as the error, replacing the if/else statement for a more DRY approach:

class MoviesController < ApplicationController
  def show
    movie = Movie.find_by(id: params[:id])
    render json: movie, status: :ok
rescue ActiveRecord::RecordNotFound
  render json: {error: "Movie not found"}, status: :not_found
  end
 end
Enter fullscreen mode Exit fullscreen mode

But there is an even DRY-er way for handling errors. If we use the .find method, ActiveRecord returns an exception that contains a more detailed error. For example, if we make a fetch request to localhost:3000/movies/99, the exception will look like:

ActiveRecord::RecordNotFound (Couldn't find Movie with 'id'=99)
Enter fullscreen mode Exit fullscreen mode

We can use this exception to generate our error and apply it to every controller with a RecordNotFound error but writing our rescue in the ApplicationController:

class ApplicationController < ActionController::API
  rescue_from ActiveRecord::RecordNotFound, with: :record_not_found
  private
  def record_not_found(error)
    render json: {error: error.message}, status: :not_found
  end
end
Enter fullscreen mode Exit fullscreen mode

Since the error is being handled inside our "top" controller, the methods in the MoviesController do not need to contain errors and therefore create a more DRY form:

class MoviesController < ApplicationController
  def show
    movie = Movie.find(params[:id])
    render json: movie, status: :ok
  end
 end
Enter fullscreen mode Exit fullscreen mode

Top comments (0)