16 March 2009

Ruby on Rails Ruby on Rails has become a rather popular framework that many have used to easily and quickly create some pretty powerful web sites. As with any web programming language or framework, it certainly does have its problems. For example, Rails has never been well-known for its incredibly speedy database layer. In fact, if you’re not careful, you can make a glorious application that will run your server into the ground because of all the heavy behind-the-scenes DB queries.

Another problem is that a lot of people get their Rails coding tips and tricks from others – basically what you’re doing right now! The solutions you find online aren’t always optimal, and are sometimes downright scary.

Take a custom 404 error page. It’s easy enough to make, but you have to be careful about how you actually implement it.

The default 404 error page is rather bland. So, you hop on your favorite search engine, and you find something like this:

Add this to the end of your config/routes.rb:

# Catch-all so we can gracefully handle badly-formed requests with a 404 Error
map.connect '*path', :controller => 'main', :action => 'missing_page'

Add this action to your main controller (or whatever you call it):

def missing_page
render :file => "#{RAILS_ROOT}/public/404.html", :layout => false and return
end

Great. That’s easy enough, and it will work. The ‘map.connect‘ part matches anything that your other routes don’t, and routes it to your missing_page action in the main controller. That action then simply displays your public/404.html file without a layout, et voila! Custom 404 error page.

So what’s the problem?

Well, first of all, some people might say that just using the 404 HTML file in your public directory isn’t good. I say that if you don’t want Rails to have to do anything, it’s perfect. I don’t care about custom messages on a 404 page. It’s just a 404 page, and serves only one purpose.

The bigger problem is the HTTP status code that will be served up with your 404.html page. Since rails is actually handling strange page requests and serving up a custom 404 action, the HTTP header for your 404 page will have the ‘200 OK’ status. You can confirm this by using something like Google Webmaster Tools. Try to validate your site in order to access your statistics and such, and Google will report that it can’t validate your site because the 404 page returns a 200 code instead of a 404 code. This makes sense since the page wasn’t “not found” – it matched the last entry in your routes.rb, Rails routed the request to the missing_page action in the main controller, and there you have it: an “OK” status code!

Fortunately, this is really easy to fix:

Add this instead to your main controller (or whatever you call it):

def missing_page
render :file => "#{RAILS_ROOT}/public/404.html", :layout => false, :status => 404 and return
end

All we did here is add the text in red, :status => 404, which tells Rails to return an HTTP status code of 404 instead of 200. And that’s what it actually should be for a 404 page!

The moral of the story is this: if you’re gonna steal your homework from somebody else, at least make sure you understand what’s going on – because it’s entirely possible that the person you stole it from doesn’t!

I never use code I don’t understand. I have found security holes, encountered problematic coding standards, and even discovered SQL queries that were unbelievably huge and slow in something as simple as a voting system plugin. In the case of the voting plugin, a buddy and I put our heads together and wrote our own voting system that was about 50 times faster – and simpler – in about 10 minutes.

So, now that you’re done reading this, get crackin’ and make sure I know what I’m talking about. And if I don’t, let me know!

Rails Custom 404 Page: Don’t Forget the Status Code!
Tagged on:     

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.