Mais em rubyonrails.pro.br: Geral | Download | Deploy | Código | Apresentações | Documentação | Ecossistema | Comunidade | Podcasts | Blogs

Roteamento Rails de fora para dentro

Este guia aborda as características do roteamento em Rails. Ao completar este guia, você será capaz de:

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

Lighthouse ticket

  • 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