Redirects in Ruby on Rails

When upgrading a legacy system to Ruby on Rails there will always be some redirects needed. The URLs for the old site will need to be mapped through to those on the new site.

For simple redirects such as from /contact to /contacts a route can be added to routes.rb such as:

get 'contact => redirect '/contacts'

Take the example where the old site used /article/foobar for articles, but on the new site we're going to to call them blog posts, so the URL will be /blog/foobar. We can therefore use the following line in routes.rb.

get 'article/:id' => redirect {|params, request| "/blog/#{params[:id]}?#{request.query_string}" }

This takes the id from the URL as passes it through as a parameter, the query string has also been added from the request just in case there are any.

For more complex redirects it's often easier to create a controller action which handles the redirect. An example would be that when this site moved from Drupal to Ruby on Rails (via Sinatra) all IDs for the blog posts were kept from Drupal. This allowed the old Drupal /node/:id paths to be used. A route was created get 'node/:id' => 'contents#node' then in the contents controller, the node action too care of the rest.

def node
  if params['id'] and params['id'].match(/^[0-9]+$/) and params['id'].length <= 3
    content = Content.where(:published => true, :id => params['id']).first
    not_found and return if !content
    redirect_to "/blog/#{content.slug}", :status => :moved_permanently
    not_found and return

You'll see here it's querying the Content model for some published content with a matching ID then redirecting to the new path with the content.slug. The not_found method is defined in application_controller.rb and just renders a 404 page. The redirect_to method is used here in the controller, this is different to the redirect used in routes.rb.

redirect_to can be used in controllers and default to a 302 redirect. :status => :moved_permanently can be added to make it a 301 redirect. 301 redirects are considered permanent and 302 redirects are not, so in the context of this post where we are looking at redirecting from a legacy path then 301 is the best bet, but if doing something like redirecting based on user authentication or access level, then 302 might be the best option. Flash messages can also be added to redirect_to, for example adding notice: "You have been redirected" will create a flash notice.

For more information on redirect in routes.rb take a look at the rails documentation, then for redirect_to take a look at the other documentation page.