Article

Latest articles →

· Tim Riley

Useful Heroku-Friendly Rewrites with rack-rewrite

On the Engine Yard blog, Kevin Rutten recently wrote about handling URL rewriting in Nginx. His opening point is that a web server like Nginx is the best possible tool for handling these rewrites, especially in comparison to doing them in your application code. Sometimes, however, configuring the web server to handle your rewrites isn’t an option, like when you’re hosting your apps on Heroku. In that case, you have no access to the web server, so any handling of URL rewriting needs to take place in your app.

There is a tool already built to handle this simply: rack-rewrite. As the name implies, it is a piece of Rack middleware for defining and applying URL rewriting rules. Using middleware to handle this makes a lot of sense because it can handle any rewriting before the requests get to your full application stack, ensuring that they happen as quickly as possible and that you don’t have any rewriting logic polluting your application code.

Installation

rack-rewrite is easy to get up and running. First, install it via the rack-rewrite gem. Then, if you have a sinatra app, you can define your rules in the config.ru rackup file:

require 'rack/rewrite'
use Rack::Rewrite do
  # rewrite rules here
end

It’s not too bad in Rails either. Set it up in config/application.rb, inside the config block:

config.middleware.insert_before(Rack::Lock, Rack::Rewrite) do
  # rewrite rules here
end

As for the kinds of rules that you can define, I’ll take you through a few examples now.

Static rewrites from old paths to new paths

This is a simple case:

r301 '/features/this-great-exhibition', '/features/great-exhibition'

Any request for the left URI will be redirected to the right URI. An r301 rewrite like this will short-circuit the rack stack and immediately send back an HTTP 301 (moved permenantly) code to the browser, along with the rewritten URL.

Rewrite to a canonical domain

This is probably one of the most useful cases for using rack-rewrite. Rewriting to a single, canonical domain name will allow you to have a “www” subdomain while still ensuring that your Google whuffie remains high. It will also stop people from accidentally browsing your site via its heroku.com subdomain, and will also be useful if you ever move from one domain name to a new one. It’s also very easy to do:

r301 %r{.*}, 'http://canonical-domain.com$&',
  :if => Proc.new { |rack_env| rack_env['SERVER_NAME'] != 'canonical-domain.com' }

Note here that you can use regular expressions to perform the URL matching. In the above case, we’re using a simple catch-all to match any request URI, and then inserting it into the rewritten URL using the $& substitution operator. We’re also using the :if option for a dynamic rule guard. The code in the Proc ensures that this rewrite only applies if the request isn’t already for the canonical domain.

Rewrite old routes to new routes

Here’s an example of transition that we recently made on Decaf Sucks, changing resource URLs for the UsersController from /users to the much friendlier /people:

r301 %r{/users(.*)}, '/people$1'

This rewrite is another example of using a regular expression. This one uses the parentheses to capture part of the original URI, then the $1 code to insert the nubmered capture into the rewritten URI.

These are just a few brief examples from our use of rack-rewrite. Check out the project page on GitHub for more examples and documentation.