Faster Ruby on Rails Routes

In this post I’ll talk about the benefits of generating your Ruby on Rails routes more quickly, and how to implement it.

Background

Rails looks at the ./config/routes.rb file to generate the mappings between URLs in your application and what controller actions those URLs correspond to. In your app, you can say redirect_to new_post_url and Rails knows that you mean http://www.panozzaj.com/posts/new (for example.)

The problem: Slow Routes Generation

Generating routes in a medium-sized Rails application could take upwards of ten seconds. This is a bit slow for feedback. Sometimes you are just exploring the routes in an application, and it could take a while to get better information. Instead of tens of seconds, why not get it down to a few seconds, or – even better – milliseconds.

Speeding Up Rails Route Generation

I’ll take an app that I am currently working on that has only a hundred or so routes defined and a bunch of gems installed. Before any changes, rake routes takes about seven seconds to generate.

One method we can use to speed up our routes query is to use Zeus to speed up the output of rake routes. This is as simple as installing Zeus, running a Zeus server, and running zeus rake routes. This change alone reduced my time for the Zeus command to about 1.25 seconds, which is about a five-fold reduction.

A further step would be saving the output of route generation to a file and looking at that directly. Once this is done, lookups are essentially instantaneous (a few milliseconds to read the file and grep through it.) This can be tricky if you are actively modifying your routes, since you might be looking at a stale route output.

routes Script

Here is a script that handles all of this for you, including using a cache file and regenerating it if needed:

#!/bin/sh

# regenerate tmp/routes if it is not already generated or it is older than the routes config file
if [ ! -f tmp/routes ] || [ tmp/routes -ot config/routes.rb ]; then
  if [ ! -f tmp/routes ]; then
    generating='Generating'
  else
    generating='Regenerating'
  fi

  [ -S .zeus.sock ] && z="zeus"

  if [ -n "$z" ]; then
    echo "$generating routes - Running under zeus."
  else
    echo "$generating routes - No Zeus enviroment detected."
  fi

  $z rake routes > tmp/routes
fi

echo "Using generated routes file."

query=$1
if [ $query ]; then
  grep $query tmp/routes
else
  cat tmp/routes
fi

Basically it will first look at ./tmp/routes to see if there is cached output there. If that file exists and it is newer than the timestamp of the ./config/routes.rb file, then use the cached version (since the routes probably haven’t changed since we last generated.) I like storing it in the ./tmp directory since it is a generated file that should be ignored from source control anyway.

If there is no cache file or it is old, look to see if zeus is running, and if it is, use it since it is faster and should give us the same results. Worst case, use the standard rake command. Regardless, save the output in the cache file for future runs.

I often do a search on the routes output, so if you pass in a parameter (example: routes posts), the script does a search on the routes output. Otherwise it just prints it out for reading or piping to another command.

A Faster Way to Generate Routes

This post covered a faster way to generate routes. I found this handy enough to write up and used it to great effect when working with a larger application that needed a conversion from Rails 2 style routes to Rails 3 style routes.

I hope that this helps you work more quickly with your routes, and let me know about any other tips for faster generation that you have used!

Kyle Shipley notes:

Categories: development

« Harvesting Artifacts For Free Blog Posts Why You Should Explain Your Android App's Requested Permissions »

Comments