Nithin Bekal Posts About

Rails: Handling Redirects in the Router

06 Jul 2016

Recently I needed to handle incoming redirects in a Rails app that didn’t map to any existing routes. It turns out that we can tell the Rails router to match a pattern and redirects it directly without writing a controller.

Say we have a Jekyll blog at, and we need to move that to our main domain as The easiest way to handle this is to set up a URL DNS record with the domain registrar that redirects all traffic coming to to

Unfortunately, our new blog has a different URL structure. All our traffic is coming to and the /posts/ part seems redundant. We’ve set up our blog routes like this:

namespace :blog do
  get '/',    to: 'posts#index'
  get '/:id', to: 'posts#show'

  resources :posts, except: [:index, :show]

To handle the new set of URLs, we could do either of these things:

# Option 1
get '/posts/:id', to: 'posts#show'

# Option 2 (posts#legacy redirects to the correct URL)
get '/posts/:id', to: 'posts#legacy'

Both of these have drawbacks. In option 1, we will now have two URLs for each blog post, which we don’t want to have to maintain.

Option 2 is better, but we’re needlessly adding another action just to handle a simple redirect. This is where I came across the option to redirect directly in the router. All you need to do is set it up like this:

namespace :blog do
  # ...
  get '/posts/:id', to: redirect('/blog/%{id}/')

The router allows you to interpolate the argument using %{}. Now we don’t have an additional action in the controller, or have to worry about having two separate URLs for the same post.

On encountering cases where you find yourself adding controller methods that do very little, it’s a good idea to look at the docs and see if the router provides a simpler way to do it.

Nithin Bekal
Hi, I’m Nithin! This is my blog about programming. Ruby is my programming language of choice and the topic of most of my articles here, but I occasionally also write about Elixir, and sometimes about the books I read. I'm @nithinbekal on Twitter.