Rails 5 Routing Cookbook: 10 receitas para o desenvolvedor novato de Rails e mais além

Você deve ter em mente que Rails é uma estrutura com opiniões e um de seus princípios subjacentes é a convenção sobre a configuração. Isso significa que a menos que você tenha uma boa razão, você não deve quebrar nenhum dos padrões acima e convenções de nomenclatura.

Por exemplo, se eu decidisse codificar a ação index como get 'cars/index' ou a ação create como post 'car/create', isso quebraria o comportamento fora da caixa do Rails para métodos helper como form_for, link_to, e redirect_to.

A consequência de quebrar convenções sem intenção é o caos e produz uma confusão que o fará lutar contra o framework por horas a fio.

>

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.

Deixe uma resposta

O seu endereço de email não será publicado.