💣 README Currently Being Updated 💣 - Gem Incorporated into 💀 VPSDeploy.com - VPS Deployment Solution 💀 -Custom Programming Tutorials
+ Deployment Infrastructure
For Cloud VPS Providers...
➡️ ExceptionHandler
is a Custom Error Pages Gem
For Ruby on Rails ⬅️ - With 160,000+ downloads, it is one of the most
popular, robust & extensible exceptions management gems for Ruby on Rails 4 & 5+...
Version 🏹 0.8.0.0
🏹 has now introduced a number of ⭐️ KEY UPGRADES ⭐️ including...
🚧 New Config Settings 🚧 ▪️ 💻 Custom Views Options 💻 ▪️ 💬 4xx
/5xx
Locales 💬...
⚠️ Tutorial shows how it works ⚠️
✉️ Support Email ✉️
Responsive Branded Error Pages Middleware Exception Handling Fully Customizable
⌚️ Introduction ⌚️
➡️ ExceptionHandler
⬅️ was designed to replace Rails' error pages (400.html
, 422.html
, 500.html
) with dynamic views...
The gem inserts a custom controller
into exceptions_app
, allowing us to render custom HTML for erroneous requests.
The controller uses a single method/view to build a response to errors. This view remains the same for every exception; the ONLY change is the layout - depending on the HTTP response being returned (4xx
/5xx
).
The beauty lies in the simplicity through which this is achieved → rather than having many different elements, its SOLE focus is to provide different HTML responses via differing layouts. ExceptionHandler
does this within the scope of ActionView
, allowing for the use of views
, helpers
and data
from the database.
Gem works 100% out of the box in production
, and has the option to be called in dev
if necessary.
--
📑 HTTP
The most important thing to understand is that it doesn't matter which errors Ruby/Rails raises - they all need to be wrapped in a valid HTTP response. Due to the nature of HTTP, you only need to facilitate responses for 4xx
- 5xx
.
This means that all you're really doing is taking "Ruby" errors and giving them an appropriate HTTP status code & message body (HTML). Rails handles the process for you - the only thing we need to worry about is how the HTML is generated.
What confuses most is the way in which Rails does this. The process is handled by ActionDispatch::ShowExceptions
- which builds a new response out of the one passed to it by the exception generator. Through this process, it calls whichever class is present in exceptions_app
...
# show_exceptions.rb
def render_exception(request, exception)
backtrace_cleaner = request.get_header "action_dispatch.backtrace_cleaner"
wrapper = ExceptionWrapper.new(backtrace_cleaner, exception)
status = wrapper.status_code
request.set_header "action_dispatch.exception", wrapper.exception
request.set_header "action_dispatch.original_path", request.path_info
request.path_info = "/#{status}"
response = @exceptions_app.call(request.env) #-> this is where the HTML is generated
response[1]["X-Cascade"] == "pass" ? pass_response(status) : response
rescue Exception => failsafe_error
$stderr.puts "Error during failsafe response: #{failsafe_error}\n #{failsafe_error.backtrace * "\n "}"
FAILSAFE_RESPONSE
end
In other words, what a user sees has very little to do with the fact Rails experienced an error. ExceptionHandler
doesn't change this behaviour - it simply adds our own controller/views setup to provide the HTML...
To better explain, there are 5️⃣ types of HTTP status code - [10x
][10x], [20x
][20x], [30x
][30x], [40x
][40x], & [50x
][50x].
Each does its own thing, but what's important is they ALL describe "responses" that your web browser will receive for HTTP requests. The only erroneous status codes are 4xx
(client error) or 5xx
(server error)...
The point is that when you're dealing with "errors" online, you're actually dealing with erroneous HTTP STATUS CODES. The response delivered with these codes is ALWAYS going to remain the same; difference lying in how they're built (on the server).
By default, NGinx
+ Apache
use "static" HTML pages to show the errors - if we're using Rails, we have the ability to create our own pages. This is exactly what our gem has been designed to do.
ExceptionHandler
provides Rails with the ability to serve dynamic exception pages, built with your *own* layouts/views. By overriding the exceptions_app
hook, it provides a custom controller
, model
and views
to display custom error pages.
The system is 100% compatible with Rails 4 & 5 and has already been downloaded 180,000+ times...
🔨 Setup 🔨
--
The most important thing to appreciate about the gem is that it's designed to be completely unobtrusive.
This means that if you're looking at using it,
Config Dev Database Email Views Locales Custom Exceptions Generators
🚧 Config 🚧
The ONLY thing you need to configure ExceptionHandler
is the config
.
Whilst the gem works out of the box (without any configuration), if you want to manage the layouts
, email
, dev
or the database
, you'll need to set the appropriate values in the config hash (invoked at init).
This can be done in config/application.rb
or config/environments/[env].rb
↴
# config/application.rb
module YourApp
class Application < Rails::Application
# => This is an example of ALL available config options
# => You're able to see exactly how it works here:
# => https://github.com/richpeck/exception_handler/blob/master/lib/exception_handler/config.rb
# => Config hash (no initializer required)
config.exception_handler = {
dev: nil, # allows you to turn ExceptionHandler "on" in development
db: nil, # allocates a "table name" into which exceptions are saved (defaults to nil)
email: nil, # sends exception emails to a listed email (string // "[email protected]")
# On default 5xx error page, social media links included
social: {
facebook: nil, # Facebook page name
twitter: nil, # Twitter handle
youtube: nil, # Youtube channel name / ID
linkedin: nil, # LinkedIn name
fusion: nil # FL Fusion handle
},
# This is an entirely NEW structure for the "layouts" area
# You're able to define layouts, notifications etc ↴
# All keys interpolated as strings, so you can use symbols, strings or integers where necessary
exceptions: {
:all => {
layout: "exception", # define layout
notification: true, # (false by default)
deliver: #something here to control the type of response
},
:4xx => {
layout: nil, # define layout
notification: true, # (false by default)
deliver: #something here to control the type of response
},
:5xx => {
layout: "exception", # define layout
notification: true, # (false by default)
deliver: #something here to control the type of response
},
500 => {
layout: "exception", # define layout
notification: true, # (false by default)
deliver: #something here to control the type of response
},
# This is the old structure
# Still works but will be deprecated in future versions
501 => "exception",
502 => "exception",
503 => "exception",
504 => "exception",
505 => "exception",
507 => "exception",
510 => "exception"
}
}
end
end
For a full retinue of the available options, you'll be best looking at the config
file itself.
--
If using an engine
, DON'T need an initializer
:
# lib/engine.rb
module YourModule
class Engine < Rails::Engine
# => ExceptionHandler
# => Works in and out of an initializer
config.exception_handler = {
dev: nil, # => this will not load the gem in development
db: true # => this will use the :errors table to store exceptions
}
end
end
The best thing about using a config
options block is that you are able to only define the options that you require. This means that if you have particular options you only wish to run in staging
, or have single options for production
etc...
💻 Dev 💻
As explained, ExceptionHandler
does not work in development
mode by default. This is because it overrides the exceptions_app
middleware hook - which is only invoked in production
or staging
...
To get it working in development
, you need to override the config.consider_all_requests_local
setting (a standard component of Rails) - setting it to "false" ↴
This is normally done by changing the setting in your Rails config files. However, to make the process simpler for ExceptionHandler
- we've added a dev
option which allows you to override the hook through the context of the gem...
# config/application.rb
config.exception_handler = { dev: true }
This disables config.consider_all_requests_local
, making Rails behave as it would in production:
![Dev][dev_img]
Obviously, this has other connotations including the likes of making your requests go through your production server etc. For this reason, it's STRONGLY recommended you only use the dev
option to test your layouts etc.
💾 Database 💾
If you want to save exceptions to your database, you will need to migrate a new
# config/application.rb
config.exception_handler = { db: true }
This enables ActiveRecord::Base
on the Exception
class, allowing us to save to the database.
In order for this to work, your db needs the correct table.
To do this, once you've enabled the option, run rails db:migrate
from your console. Our new migration system
will automatically run the migration.
✉️ Email ✉️
ExceptionHandler
also now sends email notifications.
If you want to receive emails whenever your application raises an error, you can do so by adding your email to the config:
# config/application.rb
config.exception_handler = {
email: "[email protected]"
}
Please Note this requires
ActionMailer
. If you don't have any outbound SMTP server,SendGrid
is free.
👓 Views 👓
The views system in ExceptionHandler
is modular.
What most people want out of the view is to change the way it looks. This can be done without changing the exception "view" itself...
To better explain, if ExceptionsController
is invoked (by exceptions_app
), it has ONE method (show
). This method calls the show
view, which is entirely dependent on the locales for content & the layout for the look.
This means that if you wish to change how the view "looks" - you're either going to want to change your layouts or the locales. There is NO reason to change the show
view itself - it's succinct and entirely modular. Whilst you're definitely at liberty to change it, you'll just be making the issue more complicated than it needs to be.
-
If you wish to change the "layout" / "look", there are two options...
Firstly, you can create your own layout. This is done by changing the
Secondly,
💬 Locales 💬
Locales are used to denote interchangeable text (for different languages).
We've used it for a different purpose - to provide text for our "show" view. The beauty of this is that 1) It's entirely modular & 2) It's extensible (we are able to use as many locales as required)...
[[ locales ]]
The ExceptionHandler
view is populated by @exception.description
, which pulls from the locales
.
If you want custom messages, you need the following. The key is defined by the HTTP status_code
# config/locales/en.yml
en:
exception_handler:
not_found: "Your message here"
unauthorized: "You need to login to continue"
internal_server_error: "This is a test to show the %{status} of the error"
You get access to %{message}
and %{status}
, both inferring from @exception
.
📋 Layouts 📋
![Layout][layout_img]
If you want to change the various layouts, you need to use the config
to set them.
![Layout][layouts_img]
By default, 5xx
errors are shown with our [exception
layout][layout] - this can be overridden by changing the config
to use a layout of your choice. If you want to inherit the ApplicationController
layout, assign the codes to nil
.
⛔️ Custom Exceptions ⛔️
Custom Exceptions also supported in 0.7.5
Rails handles this for us - [config.action_dispatch.rescue_responses
][rescue_responses] ↴
![ActionDispatch][config.action_dispatch.rescue_responses]
You need to add to the rescue_responses
hash in your app's config (mapped to status codes
):
# config/application.rb
config.action_dispatch.rescue_responses["ActionController::YourError"] = :bad_request
Because HTTP
can only process 4xx
/ 5xx
errors, if Rails
raises an exception, it needs to assign one of the error status codes. Default is internal_server_error
- if you'd prefer your app to just return 500
errors for your custom exception, you don't need to explicitly declare them.
💼 Generators 💼
You can generate ExceptionHandler
into your own application.
[[ Generator ]]
The following commands will copy the directories...
rails g exception_handler:views
rails g exception_handler:views -v views
rails g exception_handler:views -v controllers
rails g exception_handler:views -v models
rails g exception_handler:views -v assets
rails g exception_handler:views -v views controllers models assets
If you don't include any switches, this will copy all the folders put into your app.
Each switch defines which folders you want (EG -v views
will only copy views
dir).
✔️ Migrations (deprecated) ✔️
You DON'T need to generate a migration any more.
From 0.7.5
, the migration
generator has been removed in favour of our own migration system.
The reason we did this was so not to pollute your migrations folder with a worthless file. Our migration doesn't need to be changed - we only have to get it into the database and the gem takes care of the rest...
If you set the
db
option in config, runrails db:migrate
and the migration will be run.
To rollback, use the following:
rails db:migrate:down VERSION=000000
The drawback to this is that if you remove ExceptionHandler
before you rollback the migration, it won't exist anymore. You can only fire the rollback
when you have ExceptionHandler
installed.
☎️ Support ☎️
🚨 Obviously, if you've taken the time to use the gem, it makes sense to support it 🚨!
The fastest way to get a direct response is via email.
You're also welcome to access our Issues page to contact us directly. You could also use StackOverflow...
- ⚠️ Issues ⚠️
- 🚩 StackOverflow 🚩
- ✉️ Email ✉️
- ✏️ Medium ✏️
- 🎥 YouTube 🎥 ↴
⭐ Changelog ⭐
The most important thing to appreciate is...
➡️ ExceptionHandler
is designed to provide custom error pages for Ruby on Rails. ⬅️
If you're looking at adding extra functionality (such as a debugger), you'll probably be better looking at the likes of better_errors
or gaffe
. Whilst we'll certainly look at adding - or integrating - other features (if they're requested), our core intention has always been to provide an exception handling stack that was both simple and customizable.
--
What we've built so far...
👻 1.0.0.0
- [ ] TBA
🏹 0.8.0.0
- [x] README (focus on utility)
- [x] Introduction of
4xx
,5xx
,:all
for layouts config - [x] Changed
layouts
toexceptions
in config - [x] Email improvement
- [x] Streamlined migration
- [x] Updated model
👽 0.7.7.0
⚡ 0.7.0.0
- [x] Wildcard mime types
- [x] Custom exceptions
- [x] Test suite integration
- [x] Email
- [x] Model backend
- [x] Sprockets 4+
- [x] New layout
- [x] Readme / wiki overhaul
Ⓜ️ 0.6.5.0
- [x] Streamlined interface
- [x] ActiveRecord / Middleware overhaul
- [x] Supports Sprockets 4+ (
manifest.js
) - [x] Email integration
- [x] Asset overhaul & improvement
- [x] Removed dependencies
✔️ 0.5.0.0
- [x] Locales
- [x] Email notifications
- [x] Full test suite
- [x] Rails 4.2 & Rails 5.0 native (
request.env
fix) - [x] Controller fixed
- [x]
DB
fixed - [x] Legacy initializer support (more)
- [x] Rails asset management improvement
- [x] Reduced gem file size
⭕ 0.4.7.0
- [x] New config system
- [x] Fixed controller layout issues
- [x] Streamlined middleware
- [x] New layout & interface
[![404 + 500 Errors][banner]][rubygems]
ExceptionHandler
is now the • LEADING • custom error pages gem for Rails 4 & 5...
No other gem is as simple or effective at providing branded exception pages in production...
➡️ Download & Info ⬅️
[dev_mode]: readme/dev_mode.jpg [dev_img]: readme/dev.png [layouts_img]: readme/layouts.jpg [layout_img]: readme/layout.png [view_img]: readme/view.jpg [http_codes]: readme/http_codes.png [config]: readme/config.jpg [config.action_dispatch.rescue_responses]: readme/config.action_dispatch.rescue_responses.jpg [banner]: readme/banner.jpg [gem]: readme/gem.jpg [gemfile]: readme/gemfile.jpg [middleware]: readme/middleware.jpg [exceptions_app]: readme/exceptions_app.jpg [view]: readme/titles/view.jpg [dev]: readme/titles/dev.jpg [db]: readme/titles/db.png [support]: readme/titles/support.png "Support" [changelog]: readme/titles/changelog.png "Changelog" [contribution]: readme/titles/contributions.png "Contributions" [fl]: readme/fl.jpg "Frontline Utilities LTD" [profile]: https://avatars0.githubusercontent.com/u/1104431 "R Peck"
[better_errors]: https://github.com/charliesome/better_errors [layout]: app/views/layouts/exception.html.erb [status_codes]: http://guides.rubyonrails.org/layouts_and_rendering.html#the-status-option [stackoverflow]: http://stackoverflow.com/questions/ask?tags=ruby-on-rails+exception-handler [rescue_responses]: http://guides.rubyonrails.org/configuring.html#configuring-action-dispatch [latest]: https://github.com/richpeck/exception_handler/releases/latest [show_exception]: https://github.com/rails/rails/blob/4-0-stable/actionpack/lib/action_dispatch/middleware/show_exceptions.rb [exception_app]: http://guides.rubyonrails.org/configuring.html#rails-general-configuration [rubygems]: http://rubygems.org/gems/exception_handler [frontlineutilities.co.uk]: http://www.frontlineutilities.co.uk [stackoverflow.com]: http://stackoverflow.com/users/1143732/richard-peck?tab=profile [fork]: #fork-destination-box [pull]: http://github.com/richpeck/exception_handler/pulls [issues]: http://github.com/richpeck/exception_handler/issues
[10x]: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#1xx_Informational_responses [20x]: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_Success [30x]: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#3xx_Redirection [40x]: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_errors [50x]: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#5xx_Server_errors