Foto por Daniele Levis Pelusi em Unsplash>
Roteiros de Recursos Singulares
>
É possível também ter rotas para recursos singulares, ou seja, recursos que podem ser pesquisados sem especificar um :id
, como os que se aplicam a um current_user
ou current_account
. Isto pode ser conseguido usando os recursos singulares embutidos do Rails.
resource :profile
Roteiros aninhados
Por vezes precisamos aninhar recursos dentro de outros recursos. Por exemplo, se eu quiser criar uma reserva para um carro específico na minha garagem, pode ser mais conveniente pegar o :id
para aquele carro da URL ao invés de um campo oculto no formulário, que poderia ser adulterado por um usuário malicioso. A forma como criamos recursos aninhados em rails é a seguinte:
resources :cars do
resources :bookings
end
Cria todas as sete ações CRUD para reservas aninhadas em carros. Normalmente, no entanto, você não precisa de todas as sete rotas. E mesmo quando você precisa, certamente nem todas elas precisam estar aninhadas. Digamos que o que precisamos é da acção de criar uma reserva (vamos assumir a forma de criar uma reserva vive na acção de exibição do carro) e de editar e actualizar uma reserva existente. Eu preciso saber o :id
de um carro para editar/actualizar uma reserva? A resposta é obviamente não. Portanto, eu quero que minha aplicação responda às seguintes URLs:
# to CREATE a booking
POST request to http://my-ruby-garage.com/cars/:id/bookings/create# to EDIT a booking
GET request to http://my-ruby-garage.com/bookings/:id/edit# to UPDATE a booking
PATCH request to http://my-ruby-garage.com/bookings/:id/
Que estão gerando pelo seguinte código:
resources :cars do
resources :bookings, only:
end
resources :bookings, only:
Rails nos permite modificar quais das rotas padrão do CRUD devem ser geradas fornecendo um array de símbolos ou um único símbolo para a opção :only
ou seu oposto :except
.
Roteiros não CRUD
Não estamos limitados às sete rotas de recursos CRUD. Também podemos especificar rotas que se aplicam a um único recurso (rotas de membros) ou a vários recursos (rotas de recolha).
Rotas de membros
Continuando com o nosso exemplo RubyGarage, os carros podem ser estacionados ou retirados da garagem. Imaginemos que temos acções do controlador que são capazes de executar estas acções que modificam algum atributo de um carro específico.
resources :cars do
member do
patch :park
patch :remove
end
end
O acima permite-nos enviar pedidos de patch para http://my-ruby-garage.com/cars/:id/park
e http://my-ruby-garage.com/cars/:id/remove
e encontrar o carro específico no controlador antes de modificar o recurso em conformidade.
Caminhos de recolha
Da mesma forma, por vezes queremos executar alguma acção em vários recursos ao mesmo tempo. Por exemplo, talvez precisemos estacionar e remover uma coleção de carros ao mesmo tempo. Podemos usar o seguinte código:
resources :cars do
collection do
post :park, as: :bulk_park
post :remove, as: :bulk_remove
end
end
Aqui, configuramos nossa aplicação para responder a http://my-ruby-garage.com/cars/park
e http://my-ruby-garage.com/cars/remove
e, respectivamente, nomear essas ações bulk_park e bulk_remove. Lembre-se que podemos usar caminhos nomeados para gerar os caminhos URL dentro da nossa aplicação. Para construir um link de caminhos para estacionar uma coleção de carros, podemos usar:
<%= link_to "Park Cars", bulk_park_path, method: :post, class: "button" %>
Namespaced Routes
Namespaced routes prefixam o caminho URL dos recursos dentro do namespace e tentarão localizar os controladores relevantes sob um módulo com o mesmo nome do namespace. Os usos típicos para este padrão são admin namespaces e api namespaces.
namespace :factory do
resources :cars
end
Este exemplo constrói as seguintes rotas:
Prefix Verb URI Pattern Controller#Action factory_cars GET /factory/cars(.:format) factory/cars#index
POST /factory/cars(.:format) factory/cars#create factory_car GET /factory/cars/:id(.:format) factory/cars#show
PATCH /factory/cars/:id(.:format) factory/cars#update
PUT /factory/cars/:id(.:format) factory/cars#update
DELETE /factory/cars/:id(.:format) factory/cars#destroy
E o controlador teria que ser namespaced também :
class Factory::CarsController < ApplicationController
# ...
end
Scoped Routes
O método scope
permite-nos permanecer SECOS e agrupar as regras de roteamento relacionadas. Quando usado sem opções, é similar a namespace
, mas os controladores relevantes não precisam ser espaçados por um módulo.
scope :factory do
resources :cars
end
Gera as seguintes rotas:
Prefix Verb URI Pattern Controller#Action factory_cars GET /factory/cars(.:format) cars#index
POST /factory/cars(.:format) cars#create factory_car GET /factory/cars/:id(.:format) cars#show
PATCH /factory/cars/:id(.:format) cars#update
PUT /factory/cars/:id(.:format) cars#update
DELETE /factory/cars/:id(.:format) cars#destroy
Escopo suporta três opções: módulo, caminho e as.
Dizemos que temos um assistente de múltiplos passos para criar um novo carro na fábrica que é manuseado por um controlador que vive num módulo wizards. Queremos que o caminho apareça no browser como http://my-ruby-garage.com/create-a-car
e que seja capaz de referenciar este caminho dentro da nossa aplicação como create_car
. Existe um módulo Wizard::Car
que conhece cada passo do assistente.
scope module: 'wizards', path: 'create-a-car', as: 'create_car' do
Wizard::Car::STEPS.each do |step|
get step, to: "cars##{step}"
end
post :validate-step, to: 'cars#validate_step'
end
O código acima cria o mesmo padrão para cada passo. Por exemplo, o passo1 é acessível no navegador através da URL http://my-ruby-garage.com/create-a-car/step1
, seu formulário correspondente submete um pedido de postagem para http://my-ruby-garage.com/create-a-car/validate-step
, e o caminho pode ser chamado chamando create_car_step1_path
.
Route Redireciona
Rails também nos permite fazer redirecionamentos diretamente em routes.rb
. No exemplo anterior, talvez eu queira que qualquer um que pouse em http://my-ruby-garage.com/create-a-car
seja automaticamente redirecionado para o primeiro passo. Isto pode ser feito com o seguinte código:
get 'create-a-car',
to: redirect("/create-a-car/#{Wizard::SpotAccount::STEPS.first}")
Padrão de rota
Pode definir parâmetros padrão em uma rota passando um hash para a opção :defaults
.
resources :cars do
collection do
get :export, defaults: { format: 'csv' }
end
end
Usando isto, visitando http://my-ruby-garage.com/cars/export
irá chamar a ação de exportação no controlador de carros e a ação correspondente do controlador irá responder com um csv por padrão.
Route Globbing
Usando segmentos wildcard (fragmentos prefixados com uma estrela), podemos especificar que as partes restantes de uma rota devem ser ajustadas a um parâmetro particular. Isto é chamado de route globbing.
get '/rent/*slugs', to: 'cars#index', as: :rent_cars
Esta rota deve corresponder a http://my-ruby-garage.com/rent/lisbon/suv-sedan
e definir os parâmetros para “lisbon/suv-sedan”. Isto poderia então ser usado num sistema de procura ou filtragem contra a nossa base de dados para encontrar carros em Lisboa do tipo suv ou sedan.
Estou a escrever uma gem Slugcatcher com esta funcionalidade em mente para etiquetar modelos Rails que podem ser procurados como route slugs.