Acabei de atualizar meus modelos para usar slugs instalando a gema Stringex . Agora eu queria redirecionar aqueles URLs antigos que meus usuários conhecem e usam para os novos URLs de slug.
/answers/3 => /answers/everything
Mas, uma vez que alguém poderia propor algum título de resposta com dígitos completos (qualquer que seja a pergunta), ainda devemos permitir URLs com dígitos completos como:
/answers/42
Claro, no caso improvável de alguém clicar em um link desatualizado como / answers / 42 com 42 não sendo um slug, mas um ID de antes da mudança de rota – enquanto, nesse ínterim, outra pessoa criou uma nova resposta com aquele título de dígito, ele não obterá a resposta que procurava. Mas hey, ainda será uma resposta!
Solução
Desative a rota #show padrão e crie uma #show rota que aceite um ID ou slug.
# config/routes.rb
resources :answers, :except => :show
get "answers/:id_or_slug" => 'answers#show', :as => :answer
Em seguida, aprimore a ação #show do seu controlador para redirecionar com um 301 (movido permanentemente) se nenhuma instância foi encontrada usando o slug, mas usando o ID. E gere um RoutingError se nenhuma instância for encontrada.
# app/controllers/answers_controller.rb
def show
@answer = Answer.find_by_url(params[:id_or_slug])
if @answer.nil?
@answer = Answer.find_by_id(params[:id_or_slug])
if @answer.nil?
raise ActionController::RoutingError.new('Not Found')
else
redirect_to @answer, :status => 301
end
end
end
Observação: se você estiver usando carregadores de recursos como CanCan, será necessário desativar o carregamento de recursos para a ação #show:
# app/controllers/answers_controller.rb
load_and_authorize_resource :except => :show, :find_by => :url
authorize_resource :only => :show