How does one implement dynamic, custom error pages in Rails?
For example a custom 404 error page using your application.html.erb layout and some dynamic fields in the page.
Also, how does one test this from a local machine?
How does one implement dynamic, custom error pages in Rails?
For example a custom 404 error page using your application.html.erb layout and some dynamic fields in the page.
Also, how does one test this from a local machine?
Check Henrik Nyh's post out. Others too can be found via google.
The idea behind: Rails seems to rendering public\404.html
for 404 errors.
ActionController::Rescue
defines a rescue_action_in_public
that calls render_optional_error_file
.
Hi,
just add the following to your ApplicationController:
rescue_from ActiveRecord::RecordNotFound, :with => :render_record_not_found
# Catch record not found for Active Record
def render_record_not_found
render :template => "shared/catchmissingpage", :layout => false, :status => 404
end
# Catches any missing methods and calls the general render_missing_page method
def method_missing(*args)
render_missing_page # calls my common 404 rendering method
end
# General method to render a 404
def render_missing_page
render :template => "shared/catchmissingpage", :layout => false, :status => 404
end
You can customize the render call (use your templates, use a layout etc.) and catch errors this way. Now it catches missing method and record_not_found for you, but maybe there are cases where you want to display a 500 Error page so you can just go ahead, use this approach and make it fit for you.
For testing from a local machine, it just works like that. if you only want it to work in production mode, add a
if ENV['RAILS_ENV'] == 'production'
and you're fine.
If you do decide to create a dynamic 404 (or other status code) page be sure to remove the corresponding html file from /public
(if it exists)
I looked at a few blog posts on Google on how to do this, unfortunately most seem to rely on polluting your ApplicationController.
What I did instead was to create a template with the 404 message then use that template to update the public/404.html file from a rake task:
# Rake file to generate static 404 page
file "public/404.html" => ["app/views/layouts/application.html.erb"] do |t|
print "Updating 404 page\n"
`curl --silent http://locahost/content/error404 -o public/404.html`
end
Now whenever I update my global layout the 404 page gets updated automatically.
On the testing front, a really good way to do this (for development purposes, at least) is to use Passenger and set the rails environment to production (or comment out "RailsEnv development" in the site config). At least this way you can mimic how it works in production.
But, to get this done, I have a variety of settings files that get parsed on startup and are picked up based on the environment. One of the settings is whether to show error pages (AppSettings.show_page_errors?). Then in my Application Controller, I have
if !AppSettings.show_page_errors?
alias_method :rescue_action_locally, :rescue_action_in_public
end
So, it is generally set to the default settings, but sometimes I really need to see what exactly is going on, so I can turn it off on production.
The other step is to use custom pages. In my case, I have templates based on the error that also include a form to submit to google forms (since my server may be broken). To do that, put this (and change as needed) in your Application Controller:
def render_optional_error_file(status_code)
status = interpret_status(status_code)
render :template => "/errors/#{status.to_s[0,3]}.html.haml", :status => status, :layout => 'application.html.haml' if [404, 422, 500].include?(status)
render :template => "/errors/unknown.html.haml", :status => status, :layout => 'application.html.haml' unless [404, 422, 500].include?(status)
end
This will render the status codes 404, 422, and 500 using the template, but otherwise it uses unknown. If you need to handle others, it's just a matter of updating this method and adding the template.