I just updated my models to use slugs by installing the Stringex gem. Now I wanted to redirect those old URLs that my users know and use to the new slug URLs.
/answers/3 => /answers/everything
But since someone could come up with some full digit answer title (whatever the question) we should still allow full digit URLs like:
Sure, in the unlikely case that someone clicked on an outdated link like /answers/42 with 42 being not a slug, but an ID from before the route changed - while in the meantime someone else created a new answer with that digit title, he will not get the answer he was looking for. But hey, it'll be still an answer!
Disable the default #show route and create a #show route that accepts an ID or slug.
resources :answers, :except => :show
get "answers/:id_or_slug" => 'answers#show', :as => :answer
Then enhance your controller's #show action to redirect with a 301 (Moved Permanently) if no instance was found using the slug, but using the ID. And raise a RoutingError if no instance was found at all.
@answer = Answer.find_by_url(params[:id_or_slug])
@answer = Answer.find_by_id(params[:id_or_slug])
raise ActionController::RoutingError.new('Not Found')
redirect_to @answer, :status => 301
Note: If you're using resource loaders like CanCan, you'll need to disable resource loading for the action #show:
load_and_authorize_resource :except => :show, :find_by => :url
authorize_resource :only => :show