1 A dupla finalidade do roteamento
Roteamento Rails é um mecanismo de duplo-sentido – mais ou menos como se você pudesse transformar árvore em papel, e depois transformar papel de volta em árvore. Especificamente, ambos conectam as solicitações HTTP entrantes com os controllers da aplicação, e ajuda você a gerar URLs sem ter que arduamente codificá-las como strings.
1.1 Conectando URLs com o código
Quando sua aplicação Rails recebe uma solicitação HTTP de entrada, diz
GET /patients/17
a engine de roteamento dentro do Rails é a parte do código que envia a solicitação para o local apropriado na sua aplicação. Neste caso, a aplicação provavelmente executaria a action show dentro do controller patients, mostrando os detalhes do paciente cujo ID é 17.
1.2 Gerando URLs do código
O roteamento também funciona no caminho reverso. Se sua aplicação contém este código:
@patient = Patient.find(17)
<%= link_to "Patient Record", patient_path(@patient) %>
Então a engine de roteamento é a parte que traduz o link para a URL, assim como http://example.com/patients/17. Usando o roteamento desta maneira, você pode reduzir a fragilidade da sua aplicação se comparada com uma aplicação com URLs arduamente codificada e torna seu código fácil de ler e entender.
Patient necessita ser declarado como um recurso para que este estilo de tradução por rotas nomeadas esteja disponível.
2 Rápido Tour de Routes.rb
Há dois componentes para roteamento no Rails: a própria engine de roteamento, que é fornecida como parte do Rails, e o arquivo config/routes.rb, que contém as rotas atuais que serão usadas por sua aplicação. Aprender exatamente o que você pode colocar em routes.rb é o propósito principal deste guia, mas antes vamos obter uma rápida visão geral.
2.1 Processando o arquivo
Em formato, routes.rb não é nada mais que um grande bloco enviado para ActionController::Routing::Routes.draw. Dentro do bloco, você pode ter comentários, mas é provável que a maior parte de seu conteúdo seja de linhas individuais de código – cada linha sendo uma rota na sua aplicação. Você encontrará cinco tipos principais de conteúdo neste arquivo:
- Rotas RESTful (RESTful Routes)
- Rotas Nomeadas (Named Routes)
- Rotas Aninhadas (Nested Routes)
- Rotas Regulares (Regular Routes)
- Rotas Padrão (Default Routes)
Cada um desses tipos de rotas serão cobertos em mais detalhes, posteriormente neste guia.
O arquivo routes.rb é processado de cima para baixo quando chega uma requisição. A requisição será despachada para a primeira rota que combine. Se nenhuma rota combina, então o Rails retorna o status HTTP 404 ao chamador.
2.2 Rotas RESTful
Rotas RESTful tiram vantagem da orientação do REST embutido no Rails para empacotar muitas das informações de roteamento em uma simples declaração. Uma rota RESTful se parece como esta:
map.resources :books
2.3 Rotas Nomeadas
Rotas nomeadas dão a você links muito legíveis no seu código, bem como manipulação de solicitações recebidas. Veja aqui uma típica rota nomeada:
map.login '/login', :controller => 'sessions', :action => 'new'
2.4 Rotas Aninhadas
Rotas aninhadas permitem a você declarar que um recurso está contido dentro de outro recurso. Você verá mais tarde como pode traduzir para as URLs e caminhos no seu código. Por exemplo, se sua aplicação incluir parts, cada uma das quais pertence a um assembly, você pode declarar esta rota aninhada como:
map.resources :assemblies do |assemblies|
assemblies.resources :parts
end
2.5 Rotas Regulares
Em muitas aplicações, você verá roteamentos não RESTful, que conecta explicitamente cada parte da URL a uma ação em particular. Por exemplo,
map.connect 'parts/:number', :controller => 'inventory', :action => 'show'
2.6 Rotas Padrão
As rotas padrão são uma rede de proteção para tratar requisições sem uma rota pré-definida. Muitas aplicações Rails contém este par de rotas como padrão:
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
Estas rotas padrão são geradas automaticamente quando você cria uma nova aplicação Rails. Se você está usando roteamento RESTful para tudo na sua aplicação, você provavelmente precisará removê-las. Mas verifique se você não está usando rotas padrões antes de removê-las.
3 Roteamento RESTful: o Padrão Rails
Roteamento RESTful é o padrão atual de roteamento no Rails, e a única que você deve escolher para novas aplicações. Pode demorar um pouco enquanto você entende como funciona o roteamento RESTful, mas vale o esforço; seu código será mais fácil de ser lido e você estará trabalhando com o Rails, ao invés de lutar contra ele, quando você usa este estilo de roteamento.
3.1 O que é REST?
A fundação do roteamento RESTful é geralmente considerada a tese de doutorado de Roy Fielding, Architectural Styles and the Design of Network-based Software Architectures. Felizmente, você não precisa ler este documento inteiramente para entender como o REST funciona no Rails. REST é um acrônimo para Representational State Transfer, que resume-se em dois princípios fundamentais para nossos propósitos:
- Usando identificadores de recurso (na qual, para o propósito da discussão, você pode pensar como as URLs) para representar recursos
- Transferindo representações de estados entre recursos e componentes do sistema.
Por exemplo, para uma aplicação Rails, uma requisição como esta:
DELETE /photos/17
seria entendida como uma referencia a um recurso photo com o ID 17, e indicaria a ação desejada – deletar este recurso. REST é um estilo natural para a arquitetura de aplicações web e Rails faz isso de uma forma mais natural, usando convenções para proteger você de algumas complexidades do RESTful.
3.2 CRUD, Verbos e Ações
No Rails, uma rota RESTful fornece o mapeamento entre verbos HTTP, ações de controladores, e (implicitamente) as operações CRUD no banco de dados. Uma entrada única no arquivo de roteamento, como essa
map.resources :photos
cria sete diferentes rotas na sua aplicação:
| HTTP verb | URL | controller | action | used for |
|---|---|---|---|---|
| GET | /photos | Photos | index | mostra a lista de todas as fotos |
| GET | /photos/new | Photos | new | retorna um formulário HTML para a criação de uma nova foto |
| POST | /photos | Photos | create | cria uma nova foto |
| GET | /photos/1 | Photos | show | mostra uma foto específica |
| GET | /photos/1/edit | Photos | edit | retorna um formulário HTML para edição da foto |
| PUT | /photos/1 | Photos | update | atualiza uma foto específica |
| DELETE | /photos/1 | Photos | destroy | apaga uma foto específica |
Para estas rotas específicas (aquelas que fazem referencia a um único recurso), o identificador do recurso deverá estar disponível na ação correspondente de um controlador como params[:id].
Se você consistentemente usar rotas RESTful na sua aplicação, você deverá desabilitar as rotas padrões em routes.rb de modo que o Rails forçará a aplicação do mapeamento entre verbos HTTP e rotas.
3.3 URLs e Caminhos
Criando uma rota RESTful também tornará disponível um monte de helpers dentro da sua aplicação:
- photos_url e photos_path mapeia o caminho para as ações index e create.
- new_photo_url e new_photo_path mapeia o caminho para a ação new
- edit_photo_url e edit_photo_path mapeia o caminho para a ação edit
- photo_url e photo_path mapeia o caminho para as ações show, update e destroy
Porque o roteamento utiliza verbos HTTP assim como o caminho no pedido para expedir requisições, as sete rotas geradas pelo roteamento RESTful só dão origem a quatro pares de helpers.
Em cada caso, o helper _url gera uma string contendo toda a URL que a aplicação irá entender, enquanto o helper _path gera uma string contendo um caminho relativo para a raiz da aplicação. Por exemplo:
photos_url # => "http://www.example.com/photos"
photos_path # => "/photos"
3.4 Definindo Múltiplos Recursos ao Mesmo Tempo
Se você precisa criar rotas para mais de um recurso RESTful, você pode diminuir um pouco a digitação, definindo todas elas com uma simples chamada para map.resources:
map.resources :photos, :books, :videos
Isto tem exatamente o mesmo efeito de
map.resources :photos
map.resources :books
map.resources :videos
3.5 Recursos Singulares
Você pode também aplicar o roteamento RESTful para um único recurso dentro da sua aplicação. Neste caso, você usa map.resource em vez de map.resources e a geração das rotas é ligeiramente diferente. Por exemplo, uma entrada para o roteamento
map.resource :geocoder
cria seis rotas diferentes na sua aplicação:
| HTTP verb | URL | controller | action | used for |
|---|---|---|---|---|
| GET | /geocoder/new | Geocoders | new | retorna um formulário HTML para criação de um novo geocoder |
| POST | /geocoder | Geocoders | create | cria um novo geocoder |
| GET | /geocoder | Geocoders | show | mostra um e somente um recurso geocoder |
| GET | /geocoder/edit | Geocoders | edit | retorna um formulário HTML para edição do geocoder |
| PUT | /geocoder | Geocoders | update | atualiza um e somente um recurso do geocoder |
| DELETE | /geocoder | Geocoders | destroy | apaga um recurso geocoder |
Mesmo que o nome do recurso seja singular em routes.rb, o controlador correspondente continua no plural.
Uma rota RESTful singular gera um conjunto abreviados de helpers:
- new_geocoder_url e new_geocoder_path mapeia o caminho para a ação new
- edit_geocoder_url e edit_geocoder_path mapeia o caminho para a ação edit
- geocoder_url e geocoder_path mapeia o caminho para as ações create, show, update e destroy.
3.6 Customizando Recursos
Embora as convenções de roteamento RESTful provavelmente sejam suficientes para muitas aplicações, existe inúmeras formas de customizar a forma como uma rota RESTful funciona. Estas opções incluem:
- :controller
- :singular
- :requirements
- :conditions
- :as
- :path_names
- :path_prefix
- :name_prefix
Você também pode adicionar rotas adicionais por meio das opções :member e :collection, as quais serão discutidos mais tarde neste guia.
3.6.1 Usando :controller
A opção :controller permite você usar o nome do controlador diferente do nome do recurso público. Por exemplo, esta entrada no roteamento:
map.resources :photos, :controller => "images"
reconhecerá o recebimento de URLs contendo photo mas encaminhará (route) as requisições para o controlador Images :
| HTTP verb | URL | controller | action | used for |
|---|---|---|---|---|
| GET | /photos | Images | index | mostra a lista de todas as imagens |
| GET | /photos/new | Images | new | retorna um formulário HTML para criação de uma nova imagem |
| POST | /photos | Images | create | cria uma nova imagem |
| GET | /photos/1 | Images | show | mostra uma imagem específica |
| GET | /photos/1/edit | Images | edit | retorna um formulário HTML para edição da imagem |
| PUT | /photos/1 | Images | update | atualiza uma imagem específica |
| DELETE | /photos/1 | Images | destroy | apaga uma imagem específica |
Os helpers serão gerados com o nome do recurso, não com o nome do controlador. Portanto neste caso você receberá photos_path, new_photo_path, e assim por diante.
3.7 ‘Namespaces’ de Controladores e Roteamento
Rails permite que você agrupe seus controladores dentro de ‘namespaces’ salvando dentro de pastas debaixo de app/controllers. A opção :controller fornece uma forma conveniente para usar essas rotas. Por exemplo, você pode ter um recurso cujo controlador é apenas para administração de usuários na pasta admin:
map.resources :adminphotos, :controller => "admin/photos"
Se você usa namespaces de controlador, você precisa ter cuidado com uma sutileza no código de roteamento do Rails: ele sempre tenta preservar a maior parte possível do namespace da requisição anterior. Por exemplo, se você estiver em uma visão gerada pelo helper adminphoto_path, e você seguir um link gerado com <%= link_to "show", adminphoto(1) %> você acabará na visão gerada por admin/photos/show mas você vai acabar no mesmo lugar se você tiver <%= link_to "show", {:controller => "photos", :action => "show"} %> por quê Rails gerará a URL show relativa a URL atual.
Se você quiser garantir que o link vá para um controlador de nível superior, use uma barra precedendo o nome do controlador: <%= link_to "show", {:controller => "/photos", :action => "show"} %>
Você pode especificar o namespace do controlador com a opção :namespace ao invés do caminho:
map.resources :adminphotos, :namespace => "admin", :controller => "photos"
Isso pode ser especialmente útil quando combinada com with_options para mapear múltiplas rotas com namespace, juntas:
map.with_options(:namespace => "admin") do |admin|
admin.resources :photos, :videos
end
Isso irá lhe dar o roteamento para os controladores admin/photos e admin/videos.
3.7.1 Usando :singular
Se por alguma razão o Rails não está fazendo o que você deseja ao converter o nome do recurso do plural para o singular em um rota membro, você pode substituir sua opinião com a opção :singular:
map.resources :teeth, :singular => "tooth"
Dependendo de outros códigos na sua aplicação, você pode optar em adicionar regras adicionais para a classe Inflector.
3.7.2 Usando :requirements
Você pode usar a opção :requirements em uma rota RESTful para impor um formato para parâmetro :id implicado em rotas singulares. Por exemplo:
map.resources :photos, :requirements => { :id => /[A-Z][A-Z][0-9]+/ }
Esta declaração obriga o parâmetro combinar com a expressão regular fornecida. Então, neste caso, /photos/1 não será reconhecida por esta rota, mas /photos/RR27 será.
3.7.3 Usando :conditions
Condições no roteamento Rails são usadas atualmente apenas para ajustar o verbo HTTP para rotas individuais. Apesar de na teoria você poder ajustar isto para as rotas RESTful, na prática não há uma boa razão para fazer isso. (Você aprenderá mais sobre condições na discussão de roteamento clássico depois neste guia)
3.7.4 Usando :as
A opção :as permite que você sobrescreva o nomeamento normal para os paths gerados atualmente. Por exemplo:
map.resources :photos, :as => "images"
reconhecerá URLs recebidas contendo image mas encaminhará (route) as requisições para o controlador Photos:
| HTTP verb | URL | controller | action | used for |
|---|---|---|---|---|
| GET | /images | Photos | index | mostra a lista de todas as fotos |
| GET | /images/new | Photos | new | retorna um formulário HTML para criação de uma novo foto |
| POST | /images | Photos | create | cria uma nova foto |
| GET | /images/1 | Photos | show | mostra uma foto específica |
| GET | /images/1/edit | Photos | edit | retorna um formulário HTML para edição de uma foto |
| PUT | /images/1 | Photos | update | atualiza uma foto específica |
| DELETE | /images/1 | Photos | destroy | apaga uma foto específica |
Os helpers irão ser gerados com o nome do recurso, não o nome do path. Portanto, neste caso, você ainda obterá photos_path, new_photo_path, e assim por diante.
3.7.5 Usando :path_names
A opção :path_names permite que você sobrescreva os segmentos “new” e “edit” gerados automaticamente nas URLs:
map.resources :photos, :path_names => { :new => 'make', :edit => 'change' }
Isto faria com que o roteamento reconhecesse URLs como
/photos/make /photos/1/change
Os nomes das ações atuais não serão alterados por esta opção; as duas URLs mostradas ainda encaminharão as requisições para as ações new e edit.
Se você está querendo mudar esta opção de modo uniforme para todas as suas rotas, você pode definir um padrão em seu environment:
config.action_controller.resources_path_names = { :new => 'make', :edit => 'change' }
3.7.6 Usando :path_prefix
A opção :path_prefix permite que você adicione parâmetros adicionais que serão prefixadas para os caminhos reconhecidos. Por exemplo, suponha que cada foto na sua aplicação pertença a um fotografo em particular. No caso, você deve declarar esta rota:
map.resources :photos, :path_prefix => '/photographers/:photographer_id'
Rotas reconhecidas por esta entrada incluem:
/photographers/1/photos/2 /photographers/1/photos
Na maioria dos casos, é mais simples de reconhecer URLs deste tipo criando recursos aninhados, como discutido na próxima seção
Você também pode usar :path_prefix com rotas não RESTful.
3.7.7 Usando :name_prefix
Você pode usar a opção :name_prefix para evitar colisões entre rotas. Isto é mais usando quando você tem dois recursos com o mesmo nome que usam :path_prefix para mapear diferentemente. Por exemplo:
map.resources :photos, :path_prefix => '/photographers/:photographer_id', :name_prefix => 'photographer_'
map.resources :photos, :path_prefix => '/agencies/:agency_id', :name_prefix => 'agency_'
Com esta combinação você irá receber helpers tais como photographer_photos_path e agency_edit_photo_path para usar no seu código.
Você pode usar :name_prefix com rotas não RESTful.
3.7.8 Usando :only e :except
Por padrão, Rails cria rotas para sete das ações padrão (index, show, new, create edit, update, and destroy) para cada rota RESTful de sua aplicação. Você pode usar as opções :only e :except para fazer um ajuste fino neste comportamento. A opção :only especifica que apenas certas rotas devem ser geradas:
map.resources :photos, :only => [:index, :show]
Com esta declaração, a requisição GET para /photos teria sucesso, mas uma requisição POST para /photos (a qual deve ser normalmente encaminhada para a ação create) falharia.
A opção :except especifica a rota ou lista de rotas que não devem ser geradas:
map.resources :photos, :except => :destroy
Neste caso, todas as rotas normais exceto a rota para destroy (uma requisição DELETE para /photos/id) serão geradas.
Adicionalmente para uma ação ou lista de ações, você pode fornecer os symbols especiais :all ou :none para as opções :only e :except.
Se sua aplicação tem muitas rotas RESTful, usar :only e :except para gerar apenas as rotas que você necessita atualmente pode diminuir o uso de memória e aumentar a velocidade do processo de roteamento.
3.8 Recursos aninhados
É comum ter recursos que são logicamente filhos de outros recursos. Por exemplo, suponha que a sua aplicação inclua os seguintes modelos:
class Magazine < ActiveRecord::Base
has_many :ads
end
class Ad < ActiveRecord::Base
belongs_to :magazine
end
Cada ad é logicamente subordinado a uma magazine. Rotas aninhadas permite que você capture o relacionamento no seu roteamento. Neste caso, você deve incluir nas suas rotas a declaração:
map.resources :magazines do |magazine|
magazine.resources :ads
end
Mais abaixo você aprenderá sobre um conveniente atalho para esta construção:
map.resources :magazines, :has_many => :ads.
Além das rotas para magazines, esta declaração também criará rotas para ads, cada uma das quais exige a especificação de uma magazine na URL:
| verbo HTTP | URL | controlador | ação | usado por |
|---|---|---|---|---|
| GET | /magazines/1/ads | Ads | index | mostra a lista de todas as ads para uma magazine específica |
| GET | /magazines/1/ads/new | Ads | new | retorna um formulário HTML para criação de um novo ad pertencente a uma magazine específica |
| POST | /magazines/1/ads | Ads | create | cria um novo ad pertencente a uma magazine específica |
| GET | /magazines/1/ads/1 | Ads | show | mostra um específico ad pertencente a uma magazine específica |
| GET | /magazines/1/ads/1/edit | Ads | edit | retorna um formulário HTML para edição de um ad pertencente a uma magazine específica |
| PUT | /magazines/1/ads/1 | Ads | update | atualiza um específico ad pertencente a uma magazine específica |
| DELETE | /magazines/1/ads/1 | Ads | destroy | apaga um ad específico pertencente a uma magazine específica |
Isso também criará helpers de roteamento assim como magazine_ads_url e edit_magazine_ad_path.
3.8.1 Usando :name_prefix
A opção :name_prefix sobrescreve um prefixo automaticamente gerado nos helpers das rotas aninhadas. Por exemplo,
map.resources :magazines do |magazine|
magazine.resources :ads, :name_prefix => 'periodical'
end
Isso irá criar helpers de roteamento como periodical_ads_url e periodical_edit_ad_path. Você ainda pode utilizar :name_prefix para esconder o prefixo completamente:
map.resources :magazines do |magazine|
magazine.resources :ads, :name_prefix => nil
end
Isso irá criar helpers de roteamento como ads_url e edit_ad_path. Note que esta chamada continua exigindo que você forneça um article id:
ads_url(@magazine)
edit_ad_path(@magazine, @ad)
3.8.2 Usando :has_one e :has_many
As opções :has_one e :has_many fornecem uma notação sucinta para rotas aninhadas simples. Use :has_one para aninhar um único recurso, ou :has_many para aninhar um recurso múltiplo:
map.resources :photos, :has_one => :photographer, :has_many => [:publications, :versions]
Isso tem o mesmo efeito deste conjunto de declarações:
map.resources :photos do |photo|
photo.resource :photographer
photo.resources :publications
photo.resources :versions
end
3.8.3 Limites para os aninhamentos
Você pode aninhar recursos dentro de outros recursos aninhados se você quiser. Por exemplo:
map.resources :publishers do |publisher|
publisher.resources :magazines do |magazine|
magazine.resources :photos
end
end
Entretanto, sem a utilização de name_prefix => nil, os recursos extremamente aninhados se tornarão rapidamente incômodos. Neste caso, por exemplo, a aplicação reconheceria URLs como
/publishers/1/magazines/2/photos/3
O helper correspondente a rota seria publisher_magazine_photo_url, exigindo que você especifique objetos para todos os níveis da árvore. Esta situação é confusa o suficiente para que um popular artigo por Jamis Buck propõe uma regra de ouro para um bom design em Rails:
Recursos nunca devem ser aninhados mais do que 1 nível de profundidade.
3.8.4 Aninhamento Superficial
A opção :shallow fornece uma solução elegante para as dificuldades de rotas extremamente aninhadas. Se você especificar esta opção a qualquer nível de roteamento, então os caminhos para recursos aninhados que referencia um membro específico (isto é, aqueles com o parâmetro :id) não usará o nome do caminho ou o nome do prefixo do recurso pai. Para ver o que isso significa, considere a seguinte configuração de rotas:
map.resources :publishers, :shallow => true do |publisher|
publisher.resources :magazines do |magazine|
magazine.resources :photos
end
end
Isso permitirá o reconhecimentos (entre outros) dessas rotas:
/publishers/1 ==> publisher_path(1) /publishers/1/magazines ==> publisher_magazines_path(1) /magazines/2 ==> magazine_path(2) /magazines/2/photos ==> magazines_photos_path(2) /photos/3 ==> photo_path(3)
Com o roteamento superficial, você somente precisa fornecer informações suficiente para identificar unicamente o recurso que você precisa para trabalhar com ele. Se você quiser, você pode combinar o aninhamento superficial com as opções :has_one e :has_many:
map.resources :publishers, :has_many => { :magazines => :photos }, :shallow => true
3.9 Geração de rotas a partir de Arrays
Além de utilizar os helpers geradores de roteamento, Rails também pode gerar rotas RESTful a partir de um array de parâmetros. Por exemplo, suponha que você tenha um conjunto de rotas geradas com essas entradas no routes.rb:
map.resources :magazines do |magazine|
magazine.resources :ads
end
Rails gerará helpers como magazine_ad_path que você pode usar na construção de links:
<%= link_to "Ad details", magazine_ad_path(@magazine, @ad) %>
Outra forma para referir a mesma rota com um array de objetos:
<%= link_to "Ad details", [@magazine, @ad] %>
Este formato é especialmente útil quando você não sabe em tempo de execução qual dos vários tipos de objetos que será usados em um link específico.
3.10 Recursos em Namespaces
É possível fazer algumas coisas muito complexas pela combinação de :path_prefix e :name_prefix. Por exemplo, você pode usar a combinação dessas duas opções para mover recursos administrativos para sua própria pasta na sua aplicação:
map.resources :photos, :path_prefix => 'admin', :controller => 'admin/photos'
map.resources :tags, :name_prefix => 'admin_photo_', :path_prefix => 'admin/photos/:photo_id', :controller => 'admin/photo_tags'
map.resources :ratings, :name_prefix => 'admin_photo_', :path_prefix => 'admin/photos/:photo_id', :controller => 'admin/photo_ratings'
A boa notícia é que se você se encontrar com este nível de complexidade, você pode parar. Rails suporta namespaced resources para colocar recursos em suas próprias pastas num piscar de olhos. Aqui está uma versão namespaced da mesma árvore de rotas:
map.namespace(:admin) do |admin|
admin.resources :photos,
:has_many => { :tags, :ratings}
end
Como você pode ver, a versão namespaced é muito mais sucinta do que do outro modo – mas ainda cria as mesmas rotas. Por exemplo, você vai ter admin_photos_url que espera encontrar um Admin::PhotosController e que corresponde a admin/photos, e admin_photos_ratings_path a qual corresponde /admin/photos/_photo_id_/ratings, esperando usar Admin::RatingsController. Mesmo você não especificando explicitamente path_prefix, o código de roteamento calculará o apropriado path_prefix para o roteamento aninhado.
3.11 Adicionando mais ações RESTful
Você não está limitado às sete rotas que o roteamento RESTful cria por padrão. Se você quiser, você pode adicionar mais rotas para membros (aqueles que se aplicam para uma única instância do recurso), novas rotas adicionais (aquelas que você aplica para a criação de novos recursos), ou mais rotas para coleções (aquelas que se aplicam para a coleção de recursos como um todo).
3.11.1 Adicionando Rotas de Membros
Para adicionar uma rota para um membro, use a opção :member:
map.resources :photos, :member => { :preview => :get }
Isso habilitará o Rails para reconhecer URLs como /photos/1/preview usando o verbo HTTP GET, e la roteará para a ação preview do controlador Photos. Também irá criar o helper de rota preview_photo.
Dentro do hash de rotas, cada nome de rota especifica um verbo HTTP que será reconhecido. Você pode usar :get, :put, :post, :delete. Caso não seja necessário restringir a rota a um verbo HTTP específico, você pode usar :any. Além disso, também é possível especificar um array de symbols com os nomes dos verbos, o que é útil caso você queira permitir mais de um verbo para uma certa rota, mas não queira usar o :any:
map.resources :photos, :member => { :prepare => [:get, :post] }
3.11.2 Adicionando Rotas de Coleção
Para adicionar rotas de coleção, use a opção :collection:
map.resources :photos, :collection => { :search => :get }
Isso habilitará o Rails a reconhecer URLs como /photos/search usando o verbo HTTP GET, e la roteará para a ação search do controlador Photos. Também criará o helper de rota search_photos.
Assim como as rotas de membros, você pode especificar um array de métodos para uma rota de coleção:
map.resources :photos, :collection => { :search => [:get, :post] }
3.11.3 Adicionando Novas Rotas
Para adicionar uma nova rota (uma que cria novos recursos), use a opção :new:
map.resources :photos, :new => { :upload => :post }
Isto habilitará o Rails para reconhecer URLs como /photos/upload usando o verbo HTTP POST, e la roteará para a ação upload do controlador Photos. Também criará o helper de rota upload_photos.
Se você precisar redefinir os métodos aceitos por uma das ações padrão, você poderá fazê-lo através de um mapeamento explícito para aquela ação. Por exemplo:
map.resources :photos, :new => { :new => :any }
Isto permitirá que a ação new seja invocada por qualquer requisição para photos/new, não importa o verbo HTTP que você use.
3.11.4 Uma nota de cuidado
Se você se encontra adicionando muitas ações extras para uma rota RESTful, é hora de parar e se perguntar se você está dissimulando a presença de outro recurso que seria melhor utilizar que o seu próprio. Quando os hashes :member e :collection se tornam um lixo, então as rotas RESTful perdem a vantagem da fácil legibilidade, que é um de seus pontos fortes.
4 Rotas Regulares
Além do roteamento RESTful, Rails suporta roteamento regular – a forma para mapear URLs para controladores e ações. Com o roteamento regular, você não recebe a massas de rotas geradas automaticamente pelo roteamento RESTful. Em vez disso, você deve configurar cada rota dentro do seu aplicativo separadamente.
Enquanto o roteamento RESTful tornou-se o padrão Rails, ainda há muitos lugares onde o simples roteamento regular funciona perfeitamente. Você pode mesclar os dois estilos jdentro de uma única aplicação. Geralmente, você deve preferir o roteamento RESTful quando possível, por quê fará com que partes de sua aplicação sejam mais fáceis de escrever. Mas não é necessario tentar forçar cada última peça da sua aplicação dentro de um framework RESTful se isto não é um bom ajuste.
4.1 Parâmetros Obrigatórios
Quando você configurar uma rota regular, você fornece uma série de símbolos que o Rails mapeia para partes de uma requisição HTTP de entrada. Dois desses símbolos são especiais: :controller mapeia para o nome do controlador na sua aplicação, e :action mapeia para o nome da ação do respectivo controlador. Por exemplo, considere uma rota Rails padrão:
map.connect ':controller/:action/:id'
Se uma requisição de entrada para /photos/show/1 é processada para esta rota (por quê a ela não correspondeu nenhuma rota prévia no arquivo), então o resultado será invocar a ação show do controlador Photos, e disponibilizar o parâmetro final (1) como params[:id].
4.2 Componentes Coringas
Você pode configurar vários símbolos coringas em uma rota regular, como você gostar. Qualquer outra coisa diferente de :controller ou :action estará disponível para a ação correspondente como parte do hash de parâmetros. Assim, se você configurar esta rota:
map.connect ':controller/:action/:id/:user_id'
Uma URL de entrada de /photos/show/1/2 será encaminhada para a ação show do controlador Photos. params[:id] será definido para 1, e params[:user_id] será definido para 2.
4.3 Texto Estático
Você pode especificar um texto estático quando cria a rota. Neste caso, o texto estático é usado somente para combinar com as solicitações de entrada:
map.connect ':controller/:action/:id/with_user/:user_id'
Esta rota deverá responder para URLs como /photos/show/1/with_user/2.
4.4 Parâmetros Querystring
O roteamento Rails automaticamente pega parâmetros de querystring e os torna disponíveis na hash params. Por exemplo, com esta rota:
map.connect ':controller/:action/:id'
Uma URL de entrada de /photos/show/1?user_id=2 será encaminhada para a ação show do controlador Photos. params[:id] será definido como 1, e params[:user_id] será definido como 2.
4.5 Definindo Padrões
Você não precisa explicitamente usar o símbolos :controller e :action juntamente com a rota. Você pode fornecer padrões para esses dois parâmetros em uma hash:
map.connect 'photo/:id', :controller => 'photos', :action => 'show'
Com esta rota, uma URL de entrada de /photos/12 será encaminhada para a ação show no controlador Photos.
Você pode definir outros padrões na rota fornecendo uma hash para a opção :defaults. Isto se aplica ainda mais para os parâmetros que não estão explicitamente definidos em outros locais na rota. Por exemplo:
map.connect 'photo/:id', :controller => 'photos', :action => 'show', :defaults => { :format => 'jpg' }
Com esta rota, solicitações URL para photos/12 serão encaminhadas para a ação show no controlador Photos, e o params[:format] será definido para jpg.
4.6 Rotas Nomeadas
Rotas regulares não precisam usar o método connect. Você pode usar qualquer outro nome para criar uma rota nomeada. Por exemplo,
map.logout '/logout', :controller => 'sessions', :action => 'destroy'
Isto fará duas coisas. Primeiro, requisições para /logout serão enviadas para o método destroy do controlador Sessions. Segundo, Rails manterá os helpers logout_path e logout_url para usar no seu código.
4.7 Requisitos de Rota
Você pode usar a opção :requirements para obrigar um formato para qualquer parâmetro na rota:
map.connect 'photo/:id', :controller => 'photos', :action => 'show',
:requirements => { :id => /[A-Z]\d{5}/ }
Isso irá responder para URLs como /photo/A12345. Você pode expressar sucintamente a mesma rota desta forma:
map.connect 'photo/:id', :controller => 'photos', :action => 'show',
:id => /[A-Z]\d{5}/
4.8 Condições na Rota
Condições na rota (introduzido com a opção :conditions) são projetados para implementar restrições nas rotas. Atualmente, somente a restrição :method é suportada.
map.connect 'photo/:id', :controller => 'photos', :action => 'show',
:conditions => { :method => :get }
Como nas condições em rotas RESTful, você pode especificar :get, :post, :put, :delete, ou :any para os métodos aceitáveis.
4.9 Englobamento de Rota
O englobamento de rota é a forma de especificar um parâmetro em particular (que deve ser o último parâmetro na rota) que deverá combinar-se com todas as partes restantes da rota. Por exemplo
map.connect 'photo/*other', :controller => 'photos', :action => 'unknown',
Esta rota deverá combinar com photo/12 ou /photo/long/path/to/12 igualmente, criando um array de caminhos como o valor params[:other]
4.10 Opções de Rotas
Você pode usar :with_options para simplificar a definição de grupos de rotas similares:
map.with_options :controller => 'photo' do |photo|
photo.list '', :action => 'index'
photo.delete ':id/delete', :action => 'delete'
photo.edit ':id/edit', :action => 'edit'
end
A importância de map.with_options está diminuindo com a introdução de rotas RESTful.
5 Formatos e respond_to
Há mais de uma forma de roteamento que pode fazer coisas diferentes dependendo das diferenças nas solicitações HTTP: pela emissão de uma resposta que corresponda com o que a requisição específica como aceitável. No roteamento Rails, você pode controlar isto em especial com o parâmetro :format na rota.
Por exemplo, considere a segunda das rotas padrões de um arquivo routes.rb padrão:
map.connect ':controller/:action/:id.:format'
Esta rota combina com requisições como /photo/edit/1.xml ou /photo/show/2.rss. Com o código apropriado, você pode publicar diferentes respostas dependendo for formato da requisição:
respond_to do |format|
format.html # return the default template for HTML
format.xml { render :xml => @photo.to_xml }
end
5.1 Especificando o Formato com um Cabeçalho HTTP
Se não houver o parâmetro :format na rota, o Rails automaticamente olhará para o cabeçalho HTTP Accept para determinar o formato desejado.
5.2 Reconhecendo tipos MIME
Por padrão, o Rails reconhece html, text, json, csv, xml, rss, atom, e yaml como tipos de respostas aceitáveis. Se você necessita de tipos além destes, você pode registrar-los no seu environment:
Mime::Type.register "image/jpg", :jpg
6 As Rotas Padrões
Quando você cria uma nova aplicação Rails, routes.rb é inicializado com essas duas rotas padrões:
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
Essas rotas fornecem razoáveis padrões para muitas URLs, se você não está usando roteamento RESTful.
O padrão de rotas fará cada ação de cada controlador da sua aplicação acessível por requisições GET. Se você conceber sua aplicação para fazer o uso consistente de RESTful e rotas nomeadas, você deve comentar as rotas padrões para prevenir o acesso a seus controladores através de verbos errados. Se você tiver as rotas padrões habilidades durante o desenvolvimento, você precisa ter certeza de que não está involuntariamente dependente delas em algum lugar da sua aplicação – de outra forma, você poderá encontrar falhas misteriosas quando você desativá-las.
7 A Rota Vazia
Não confunda as rotas padrões com a rota vazia. A rota vazia tem uma finalidade específica: para requisitar os pedidos dentro da raiz do web site. Por exemplo, se seu site é example.com, então as requisições para http://example.com ou http://example.com/ serão tratadas pela rota vazia.
7.1 Usando map.root
A forma preferida de configurar uma rota vazia é com o comando map.root:
map.root :controller => "pages", :action => "main"
O uso do método root diz ao Rails qual é a rota a ser aplicada quando for requisitada a raiz do site.
Para uma melhor legibilidade, você pode especificar uma rota já criada na chamada para map.root:
map.index :controller => "pages", :action => "main"
map.root :index
Por causa do processamento de cima para baixo do arquivo, a rota nomeada deve ser especificada antes da chamada para map.root.
7.2 Conectando a String Vazia
Você pode especificar uma rota vazia explicitamente conectando uma string vazia:
map.connect '', :controller => "pages", :action => "main"
Se a rota vazia não parece que está funcionando na sua aplicação, tenha certeza que você tenha deletado o arquivo public/index.html da sua árvore Rails.
8 Inspencionando e Testando Rotas
Roteamento na sua aplicação não deve ser uma “caixa preta” que você nunca abrirá. O Rails oferece ferramentas prontas para inspecionar e testar rotas.
8.1 Vendo Rotas Existentes com Rake
Se você precisa de uma lista de todas as rotas disponíveis na sua aplicação, execute o comando rake routes. Isso irá descarregar todas as rotas para o console, na mesma ordem que aparecem em routes.rb. Para cada rota, você verá:
- O nome da rota (se houver)
- O verbo HTTP usado (se a rota não responder para todos os verbos)
- O padrão de URL
- Os parâmetros de roteamento que serão gerados pela URL
Por exemplo, aqui é uma pequena seção da saída do rake routes para uma rota RESTful:
users GET /users {:controller=>"users", :action=>"index"}
formatted_users GET /users.:format {:controller=>"users", :action=>"index"}
POST /users {:controller=>"users", :action=>"create"}
POST /users.:format {:controller=>"users", :action=>"create"}
Você verá que a saída de rake routes é muito mais legível se você aumentar a janela do terminal até que que não precise haver quebra das linhas.
8.2 Testando Rotas
Rotas devem ser incluídas na sua estratégia de teste (assim como o resto da sua aplicação). Rails oferece três built-in assertions projetado para simplificar a criação de testes de rotas:
- assert_generates
- assert_recognizes
- assert_routing
8.2.1 A Assertion The assert_generates
Use assert_generates para afirmar que um conjunto particular de opções gera um caminho específico. Você pode usar junto com as rotas padrões ou com rotas customizadas.
assert_generates "/photos/1", { :controller => "photos", :action => "show", :id => "1" }
assert_generates "/about", :controller => "pages", :action => "about"
8.2.2 A Assertion assert_recognizes
A afirmação assert_recognizes é o inverso da assert_generates. Ela afirma que o Rails reconhece um caminhos recebidos e o encaminha para um local específico na sua aplicação.
assert_recognizes { :controller => "photos", :action => "show", :id => "1" }, "/photos/1"
Você pode fornecer o argumento :method para especificar um verbo HTTP:
assert_recognizes { :controller => "photos", :action => "create" }, { :path => "photos", :method => :post }
Você também pode usar helpers RESTful para testar o reconhecimento da rota RESTful:
assert_recognizes new_photo_url, { :path => "photos", :method => :post }
8.2.3 A Assertion assert_routing
A afirmação assert_routing verifica a rota de duas formas: testa se o caminho gera as opções, e que as opções geram o caminho. Deste modo, combina as funções de assert_generates e assert_recognizes.
assert_routing { :path => "photos", :method => :post }, { :controller => "photos", :action => "create" }
9 Changelog
- Abril, 18, 2009: revisado por Eleudson Queiroz
- March, 14, 2009: traduzido por Cairo Noleto
- 4 de Outubro de 2008: Adicionado detalhes adicionais na especificação de verbos para o recurso das rotas member/collection , por Mike Gunderloy
- 23 de Setembro de 2008: Adicionado seção em controladores namespaced e roteamento, por Mike Gunderloy
- 10 de Setembro de 2008: versão incial por Mike Gunderloy