A forma original desta resposta é muito diferente e pode ser encontrada aqui . Apenas prova de que há mais de uma maneira de esfolar um gato.
Atualizei a resposta desde então para usar namespaces e redirecionamentos 301 - em vez do padrão 302. Agradecemos a pixeltrix e Bo Jeanes pela solicitação sobre essas coisas.
Você pode usar um capacete muito forte, porque isso vai surpreender sua mente .
A API de roteamento do Rails 3 é super maliciosa. Para escrever as rotas para sua API, conforme seus requisitos acima, você precisa apenas disso:
namespace :api do
namespace :v1 do
resources :users
end
namespace :v2 do
resources :users
end
match 'v:api/*path', :to => redirect("/api/v2/%{path}")
match '*path', :to => redirect("/api/v2/%{path}")
end
Se sua mente ainda estiver intacta após esse ponto, deixe-me explicar.
Primeiro, chamamos de namespaceque é super útil quando você deseja um monte de rotas com escopo definido para um caminho e módulo específicos com nomes semelhantes. Nesse caso, queremos que todas as rotas dentro do bloco namespacetenham o escopo definido para os controladores dentro do Apimódulo e todas as solicitações de caminhos dentro dessa rota serão prefixadas api. Pedidos como /api/v2/users, você sabe?
Dentro do espaço para nome, definimos mais dois espaços para nome (woah!). Desta vez estamos definindo o namespace "v1", de modo que todas as rotas para os controladores aqui vai estar dentro do V1módulo dentro do Apimódulo: Api::V1. Ao definir resources :usersdentro dessa rota, o controlador estará localizado em Api::V1::UsersController. Esta é a versão 1, e você chega lá fazendo solicitações como /api/v1/users.
A versão 2 é apenas uma pequena pouco diferente. Em vez de o controlador atender Api::V1::UsersController, ele está agora Api::V2::UsersController. Você chega lá fazendo pedidos como /api/v2/users.
Em seguida, a matché usado. Isso corresponderá a todas as rotas da API que vão para coisas como /api/v3/users.
Esta é a parte que eu tive que procurar. A :to =>opção permite que você especifique que uma solicitação específica deve ser redirecionada para outro lugar - eu sabia disso -, mas não sabia como redirecioná-la para outro lugar e passar uma parte da solicitação original junto com ela .
Para fazer isso, chamamos o redirectmétodo e passamos uma string com um %{path}parâmetro interpolado especial . Quando chega uma solicitação que corresponde a esta final match, ele interpola o pathparâmetro no local %{path}dentro da string e redireciona o usuário para onde eles precisam ir.
Finalmente, usamos outro matchpara rotear todos os caminhos restantes prefixados /apie redirecioná-los para /api/v2/%{path}. Isso significa que solicitações como /api/usersirão para /api/v2/users.
Eu não conseguia descobrir como obter /api/asdf/userspara corresponder, porque como é possível determinar se isso é suposto ser um pedido para /api/<resource>/<identifier>ou /api/<version>/<resource>?
Enfim, foi divertido pesquisar e espero que ajude você!