Redirector: A Redirect Rule Engine for Rails Applications
Something we get asked to do again and again on projects is to add redirects for either old URLs (from legacy systems) or custom URLs for marketing campaigns. We often start with Rack::Rewrite, but often times we find ourselves in a situation where it would be better for the client to manage these redirect rules. We did it enough times that it seemed like we should stop rebuilding the same thing over and over. So today we’re pleased to release the Ruby gem Redirector! The goal here was to build something that could cover most of our use cases (and hopefully yours too) and allow others to use it and improve upon it.
Defining a redirect rule
A redirect rule matches an incoming request path and defines a redirect destination for the visitor. Sometimes this is an exact path match, however other times we need to do matches based on regular expressions. Luckily both of the databases we regularly use (MySQL and PostgreSQL) allow us to do regular expression matches inside of SQL
WHERE clauses. This allows us to match rules with just SQL.
It can also be important to interpolate match groupings from the request path into the destination path. For instance, maybe you have an incoming URL like this
/my/old/horrible/path/to/blog/post/20 needs to turn into
/news/20. You can achieve this by using
/my/old/horrible/path/to/blog/post/([0-9]+) as the source and
/news/$1 as the destination on the redirect rule.
Often we also need to further limit rules based on other HTTP headers or other parts of the request (query string, host, etc.). For this we added the concept of request environment rules that can be related to a redirect rule. These similarly can be exact matches like
HTTP_CUSTOM_HEADER needs to be “Special Value”, or they can be regular expression matches like
QUERY_STRING needs to have “my_param=value” in it. All of the environment rules attached to a redirect rule will need to be met for a redirect rule to be applied.
Finally regular expressions (both for the source and environment values) can be configured to be case sensitive or not via a column on the respective tables and thus on a record by record basis.
How it works
When you have Redirector installed it inserts a piece of Rack middleware near the top of the middleware stack. This way a request doesn't have to go through the whole Rails stack just to redirect a visitor to your site. Then it does a query on the
redirect_rules table to find matches based on the incoming request path. Exact string matches are preferred over regular expression matches and rules with longer
source values are preferred over those with shorter values. Next in Rubyland we go through each match and pick the first one whose request environment rules all match the current request environment. Finally, we interpolate any regular expression matching groups into the destination and redirect the visitor there.
Because of the power of Rails engines, installing this is fairly painless:
- Add it to your Gemfile (
gem 'redirector') and then
$ rake db:migrate
With this the redirect engine is up and running. Now all you need to do is wire up an interface for admins (or whomever should have permission) to manage the redirect rules.
If you think this will be useful to you, test it out and let us know what you think. A few more details, and of course all the code, can be found on Github. If you find there’s room for improvement go ahead and fork, hack, and submit a pull request.