Here is how we can integrate custom error pages instead of default Rails error pages, for 400(Not Found) and other Server Errors.
Following is the example code snippet :
First step is to remove the Rails default error pages from applications "public" folder.
For Production make sure you have following setting in your environment file:
Also, if you want to test the changes on your local server, do the same setting in your development env file :
Errors Layout (totally static -- for server errors only)
Error Views
And thats it.... ;)
Go and test it by raising some error in your application like: routing errors etc.
Following is the example code snippet :
First step is to remove the Rails default error pages from applications "public" folder.
Application Config
#config/application.rb
config.exceptions_app = self.routes
For Production make sure you have following setting in your environment file:
#config/production.rb
config.consider_all_requests_local = false
Also, if you want to test the changes on your local server, do the same setting in your development env file :
#config/development.rb
config.consider_all_requests_local = false
Routes
#config/routes.rb
if Rails.env.production?
get '404', :to => 'application#page_not_found'
get '422', :to => 'application#server_error'
get '500', :to => 'application#server_error'
end
Errors Controller
#controllers/errors_controller.rb
def page_not_found
respond_to do |format|
format.html { render template: 'errors/not_found_error', layout: 'layouts/application', status: 404 }
format.all { render nothing: true, status: 404 }
end
end
def server_error
respond_to do |format|
format.html { render template: 'errors/internal_server_error', layout: 'layouts/error', status: 500 }
format.all { render nothing: true, status: 500}
end
end
Errors Layout (totally static -- for server errors only)
#views/layouts/error.html.erb
<!DOCTYPE html>
<html>
<head>
<title><%= action_name.titleize %> :: <%= site_name %></title>
<%= csrf_meta_tags %>
<style>
body {
background: #fff;
font-family: Helvetica, Arial, Sans-Serif;
font-size: 14px;
}
.error_container {
display: block;
margin: auto;
margin: 10% auto 0 auto;
width: 40%;
}
.error_container .error {
display: block;
text-align: center;
}
.error_container .error img {
display: block;
margin: 0 auto 25px auto;
}
.error_container .message strong {
font-weight: bold;
color: #f00;
}
.error_container .contact_info {
display: block;
text-align: center;
margin: 25px 0 0 0;
}
.error_container .contact_info a {
display: inline-block;
margin: 0 5px;
opacity: 0.4;
transition: opacity 0.15s ease;
}
.error_container .contact_info a:hover {
opacity: 0.8;
}
</style>
</head>
<body>
<div class="error_container">
<%= yield %>
</div>
</body>
</html>
Error Views
#views/errors/not_found_error.html.erb
<div class="error">
<h2>Sorry, this page has moved, or doesn't exist!</h2>
</div>
#views/errors/internal_server_error.html.erb
<div class="error">
<%= image_tag('layouts/error/alert.png', :width => "150") %>
<div class="message">
<strong>Error!</strong>
We're sorry, but our server is experiencing problems :(
</div>
<div class="contact_info">
<%= link_to image_tag('layouts/error/contact/twitter.png'), "", :title => "Follow Updates On Twitter", :target => "_blank" %>
<%= link_to image_tag('layouts/error/contact/facebook.png'), "http://www.facebook.com/", :title => "See Progress On Facebook", :target => "_blank" %>
<%= link_to image_tag('layouts/error/contact/fusion.png'), "", :title => "Catch Our Fusion Feed Updates", :target => "_blank" %>
<%= link_to image_tag('layouts/error/contact/instagram.png'), "", :title => "See Updates On Instagram", :target => "_blank" %>
<%= link_to image_tag('layouts/error/contact/youtube.png'), "", :title => "See Updates On YouTube", :target => "_blank" %>
</div>
</div>
And thats it.... ;)
Go and test it by raising some error in your application like: routing errors etc.
Very nicely Explained..
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteThanks for the article, helped!
ReplyDeleteErrors happen not only on get methods. So in routes.rb I added:
unless Rails.application.config.consider_all_requests_local
match '404', via: :all, to: 'errors#error_404'
match '422', via: :all, to: 'errors#error_422'
match '500', via: :all, to: 'errors#error_500'
end
If user directly go to '/500', server must output 404 error.
In errors_controler.rb:
class ErrorsController < ApplicationController
protect_from_forgery except: :all
def error_404
respond_to do |format|
format.html { render action: 'error_404', status: 404 }
format.all { render status: 404, nothing: true }
end
end
def error_422
error_xxx 422
end
def error_500
error_xxx 500
end
private
def error_xxx(number)
if request.path == "/#{number}"
error_404
else
respond_to do |format|
format.html { render status: number }
format.all { render status: number, nothing: true }
end
end
end
end
Nice article, very helpful. In order for your requests to be routed properly on development, you need to do something like :
ReplyDeleteunless Rails.env.test?
get '404', :to => 'application#page_not_found'
get '422', :to => 'application#server_error'
get '500', :to => 'application#server_error'
end
on your routes.rb.
Thank you again,
JC
@Sergei Dubovsky, Thanks for your suggestions. I will update my post.
ReplyDelete