I launched JCFootballProspects.com a while ago and things have been going smoothly but the site is stuck with the nasty black-on-white error messages when somebody types in a wrong address.
I'm now at the point where I want to give out some fancy 404 pages and I've been looking around at what other folks have done. I'm amazed to find that all the examples I can find have a 404.html page in the #{RAILS_ROOT}/public directory. I'm sure it's effective to just have a plain-html file that gets served up for errors (and it's certainly a lot better than the default ugly stuff) but I'm convinced there are advantages to having application-provided 404 pages as well.
There are three different kinds of errors I trap and respond to: A user gives incorrect or insufficient parameters to a page view A user attempts to access an action that doesn't exist * A user attempts to access a controller that doesn't exist
The first is easily handled - even the AWDWR book shows in an early example that you can output a flash message if something goes wrong with a request. The second is only slightly more complicated but, luckily, Ruby has a great way to respond to missing actions on controllers using method_missing. The solution to the third is provided by Rails' routing capabilities.
The first thing I did was added a view to my default controller (mine is called 'home'). I created ./app/views/home/404.rhtml and put just some basic stuff in it:
<%= content_tag 'h2', 'Whoops!' %>
<%= content_tag 'h3', 'Page not found' %>
[insert message here]
The next step was to add method_missing to my application controller: <typo:code lang="ruby">
class ApplicationController < ActionController::Base
...
def method_missing(methodname, *args) @methodname = methodname @args = args render 'home/404', :status => 404 end
end
And one super low priority route (put it at the very bottom) finishes off the job:
map.error ':controllername', :controller => 'home',
:action => '404'
-
sasha said:
there is another more generic way that will catch all the errors, you can inspect the exception to route to the right view, and possibly log the trace:
in application.rb
-
Danger said:
That's brilliant. I'd been wondering where the default rescue page was coming from.
I won't bother to edit this post to reflect your mad new style but I hope everybody reads your comment.
-
Ben said:
Surely you can just change the error documents in /Public/...?
-
Danger said:
It's true - you can just change 400.html to read what you want.
But this allows you to customize the layout. You can still show the person logged in at the top-right of the screen (if that's your thing) along with any other session vars, you can keep your layout, and (should you be super-tricky) you can customize the message based on what they were looking for.
But you're right - 400.html is fine for a lot of folks.
-
Chris said:
The problem with using a route like "map.error ':controllername'" is that it won't catch 'mysite.com/jibberish/morejibberish'. For a brickwall catch-all route, you're best off using a wildcard route: "map.error '*url' :controller => 'home' :action => '404'"
-
Anthony said:
sorry, i don't think i quite get this. So basically, i did the changes to my application controller and added the view, modified the routes, but when i type in some rndom non-existing url, i get an error telling me that
'You called render with invalid options : application/404'
(in my case, i don't use "home", but application)
ny idea what exactly this means?
A
-
Jack Danger said:
Anthony: Try "render :template => 'application/404'"
This article badly needs to be updated.
-
Tony Mcintyre said:
teraglin nizam rendlewood reorient unenraged phonautographically reservery sulphocarbamic
Plymouth Creek Christian Church
http://www.mnpro.com/
-
sweetperceptions said:
What about custom 500 pages? it surely won't be caught by the low priority route entry.. what are your thoughts?
-
sweetperceptions said:
I just found out how to catch the 500 error messages. You can read it here: http://coderkitty.sweetperceptions.com/2008/7/6/meaningful-404s-and-500s
blog comments powered by Disqusdef rescue_action_in_public(exception) # do something based on exception message = exception.backtrace.join("\n") unless exception render :file => "#{RAILS_ROOT}/public/404.html", :layout => false, :status => 404 end def local_request? false endthanks for the CSV tip. doc is atrocious