
This post was extracted and adapted fromThe Rails and Hotwire Codex.
When something goes wrong in Rails, the user sees a rather boring default error page.
This page lives in the/public
folder and hence isn't rendered through the Rails stack.
To jazz up this page a bit, we'll create a controller to render errors so the Rails infrastructure can be used.
Setting up
A configuration change needs to be made so public facing errors are rendered in development rather than the exception and stack trace.
# config/environments/development.rbrequire"active_support/core_ext/integer/time"Rails.application.configuredo# ...config.consider_all_requests_local=falseend
Create the controller.
$ bin/rails g controller errors --no-helper --no-test-framework
This controller will have a singleshow
action where we'll extract the error code for the raised exception and render the appropriate view. Error codes403
,404
and500
will have dedicated error pages and we'll fall back to the404
page for everything else.
classErrorsController<ApplicationControllerlayout"error"defshow@exception=request.env["action_dispatch.exception"]@status_code=@exception.try(:status_code)||ActionDispatch::ExceptionWrapper.new(request.env,@exception).status_coderenderview_for_code(@status_code),status:@status_codeendprivatedefview_for_code(code)supported_error_codes.fetch(code,"404")enddefsupported_error_codes{403=>"403",404=>"404",500=>"500"}endend
As you can see, we're using a bespoke"error"
layout as well. These pages will be simple and won't need the usual baggage from the application layout.
Create the new error layout.
$ touch app/views/layouts/error.html.erb
<%# app/views/layouts/error.html.erb %><!DOCTYPE html><html><head><%=render"layouts/head"%></head><body><main><%=yield%></main></body></html>
Create the views and fill them in as you wish.
$ touch app/views/errors/403.html.erb$ touch app/views/errors/404.html.erb$ touch app/views/errors/500.html.erb
We need to now tell Rails to use this controller to render errors.
Exceptions app
Rails provides a hook to render custom errors through a configuration property calledexceptions_app
. This property has to be assigned aRack app which is invoked when an exception is raised.
Every Rails controller action is actually its own Rack application! The Rack endpoint is returned by theaction
method on a controller class.
# ...moduleMyAppclassApplication<Rails::Applicationconfig.load_defaults7.0config.exceptions_app=->(env){ErrorsController.action(:show).call(env)}endend
Restart your server and then try visiting a page that doesn't exist. Or manually trigger an error in a controller action. You'll see your custom error pages in action!
If you liked this post, check out my book,The Rails and Hotwire Codex, to level-up your Rails and Hotwire skills!
Top comments(3)

- LocationNairobi
- EducationBsc Computer Science
- WorkFull Stack Ruby on Rails at Freelance
- Joined
This is great@ayushn21 !

- LocationNairobi
- EducationBsc Computer Science
- WorkFull Stack Ruby on Rails at Freelance
- Joined
@ayushn21 I noticed this doesn't work withActionController::InvalidAuthenticityToken
look like it's a problem when a request is in a POST method.
For further actions, you may consider blocking this person and/orreporting abuse