Strange Symphonies The best way to predict the future is to invent it

6Feb/093

Building Custom Error Pages

A good error page is important in the user experience of a website. Lucky for us Ruby on Rails provides a convenient way to update any 404 (Not Found), 422 (Unprocessable Entity), and 500 (Internal Server Error) errors that occur in your application.

This is easily done by updating the files located in your Rails root at:

  • /public/404.html
  • /public/422.html
  • /public/500.html

But sadly, it's not good enough.

The Problems

The problem with is that it simply isn't flexible enough:

  • Unable to embed ruby code.
  • Requires duplicating layout code.
  • Dynamic code in layout is made static in error pages.

The Solution

Inside the ActionPack code, located in /lib/action_controller/rescue.rb File is the method rescue_action_in_public.

Lets have a look at the comment:

Overwrite to implement public exception handling (for requests answering false to local_request?). By default will call render_optional_error_file. Override this method to provide more user friendly error messages.

Bingo! Exactly what we wanted.

Firstly lets generate he simple 404, 422, and 500 error pages. Likewise I leave them in their own directory in the /app/views File folder, I like to call this directory "errors".

Hence my new files will be located like so:

  • /app/view/errors/404.html.erb
  • /app/view/errors/422.html.erb
  • /app/view/errors/500.html.erb

Now feel free to remove the error pages in your /public File directory.

Now in our ApplicationController (see /app/controllers/application.rb File ), lets add override the function rescue_optional_error_file,

class ApplicationController < ActionController::Base
  ...

  protected
    def render_optional_error_file(status_code)
      status = interpret_status(status_code)
      render :template => "/errors/#{status[0,3]}.html.erb", :status => status, :layout => 'application.html.erb'
    end

  ...
end

Note: I have to explicitly state the file extension and layout, else when an unknown format is requested

Testing

Off the bat, you cannot test this on your local machine. You are required to redefine the local_request? in the ApplicationController, like so:

class ApplicationController < ActionController::Base
  ...

  protected
    def local_request?
      true
    end

  ...
end

Now you are ready for testing out your new error pages!

Note: Don't forget to remove the local_request? when done!

Related posts

Tags

Comments (3) Trackbacks (0)
  1. I think you have typo there. The method you should be overriding is
    def rescue_optional_error_file(status_code) not
    def rescue_optional_error_file(status_code)
    This is based on the following documentation http://api.rubyonrails.org/classes/ActionController/Rescue.html
    Also def local_request? should return false not true for it to work in your development machine.

  2. I think you have typo there. The method you should be overriding is
    def render_optional_error_file(status_code) not
    def rescue_optional_error_file(status_code)
    This is based on the following documentation http://api.rubyonrails.org/classes/ActionController/Rescue.html
    Also def local_request? should return false not true for it to work in your development machine.

  3. I changed to :

    def local_request?
    false
    end

    And works like a charm. Thanks!


Leave a comment