Rails 5 Routing Cookbook : 10 recettes pour le développeur Rails novice et au-delà

Vous devez garder à l’esprit que Rails est un framework d’opinion et l’un de ses principes sous-jacents est la convention sur la configuration. Cela signifie qu’à moins d’avoir une très bonne raison, vous ne devriez pas briser l’un des modèles et des conventions de nommage ci-dessus.

Par exemple, si je décidais de coder l’action index comme get 'cars/index' ou l’action create comme post 'car/create', cela briserait le comportement Rails prêt à l’emploi pour les méthodes d’aide telles que form_for, link_to et redirect_to.

La conséquence de briser les conventions sans intention est le chaos et cela produit un désordre emmêlé qui vous fera lutter contre le framework pendant des heures.

Photo de Daniele Levis Pelusi sur Unsplash

Routes de ressources singulières

Il est également possible d’avoir des routes pour des ressources singulières, c’est-à-dire des ressources qui peuvent être recherchées sans spécifier un :id, comme celles qui s’appliquent à un current_user ou un current_account. Cela peut être réalisé en utilisant les ressources singulières intégrées de Rails.

resource :profile 

Routes imbriquées

Parfois, nous devons imbriquer des ressources à l’intérieur d’autres ressources. Par exemple, si je veux créer une réservation pour une voiture spécifique dans mon garage, il pourrait être plus pratique de saisir le :id pour cette voiture à partir de l’URL plutôt qu’un champ caché de formulaire, qui pourrait être altéré par un utilisateur malveillant. La façon dont nous créons des ressources imbriquées dans rails est la suivante :

resources :cars do 
resources :bookings
end

Cela crée les sept actions CRUD pour les réservations imbriquées dans les voitures. Habituellement, cependant, vous n’avez pas besoin des sept routes. Et même lorsque vous en avez besoin, il n’est certainement pas nécessaire qu’ils soient tous imbriqués. Disons que ce dont nous avons besoin est l’action pour créer une réservation (nous supposerons que le formulaire pour créer une réservation vit dans l’action show de la voiture) et pour modifier et mettre à jour une réservation existante. Dois-je connaître le :idd’une voiture pour modifier/mettre à jour une réservation ? La réponse est évidemment non. Par conséquent, je veux que mon application réponde aux URL suivantes:

# 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/

qui sont générées par le code suivant:

resources :cars do 
resources :bookings, only:
end
resources :bookings, only:

Rails nous permet de modifier lesquelles des routes CRUD standard doivent être générées en fournissant un tableau de symboles ou un seul symbole à l’option :only ou à son opposé :except.

Routes non CRUD

Nous ne sommes pas limités aux sept routes de ressources CRUD. Nous pouvons également spécifier des routes qui s’appliquent à une seule ressource (routes de membres) ou à plusieurs ressources (routes de collections).

Routes de membres

Poursuivons avec notre exemple RubyGarage, les voitures peuvent être garées dans le garage ou en être retirées. Imaginons que nous ayons des actions de contrôleur capables d’effectuer ces actions qui modifient un certain attribut d’une voiture spécifique.

resources :cars do 
member do
patch :park
patch :remove
end
end

Ce qui précède nous permet d’envoyer des demandes de patch à http://my-ruby-garage.com/cars/:id/park et http://my-ruby-garage.com/cars/:id/remove et de trouver la voiture spécifique dans le contrôleur avant de modifier la ressource en conséquence.

Collection routes

De la même manière, parfois nous voulons effectuer une certaine action sur plusieurs ressources en même temps. Par exemple, nous avons peut-être besoin de garer et de retirer une collection de voitures en même temps. Nous pouvons utiliser le code suivant:

resources :cars do 
collection do
post :park, as: :bulk_park
post :remove, as: :bulk_remove
end
end

Ici, nous configurons notre application pour répondre à http://my-ruby-garage.com/cars/park et http://my-ruby-garage.com/cars/remove et, respectivement, nommer ces actions bulk_park et bulk_remove. Rappelez-vous que nous pouvons utiliser des chemins nommés pour générer les chemins URL à l’intérieur de notre application. Pour construire un lien de chemin d’accès pour garer une collection de voitures, nous pourrions utiliser :

<%= link_to "Park Cars", bulk_park_path, method: :post, class: "button" %>

Routes nommées

Les routes nommées préfixent le chemin d’accès URL des ressources à l’intérieur du bloc d’espace de nom et essaieront de localiser les contrôleurs pertinents sous un module portant le même nom que l’espace de nom. Les utilisations typiques de ce modèle sont les espaces de noms d’admin et les espaces de noms d’api.

namespace :factory do 
resources :cars
end

Cet exemple construit les routes suivantes :

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

Et le contrôleur devrait aussi être namespaced :

class Factory::CarsController < ApplicationController
# ...
end

Routes scopées

La méthode scope nous permet de rester DRY et de regrouper les règles de routage connexes. Lorsqu’elle est utilisée sans options, elle est similaire à namespace, mais les contrôleurs concernés n’ont pas besoin d’être namespaced avec un module.

scope :factory do 
resources :cars
end

Génère les routes suivantes:

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

Scope supporte trois options : module, path et as.

Disons que nous avons un assistant à plusieurs étapes pour créer une nouvelle voiture dans l’usine qui est géré par un contrôleur vivant dans un module wizards. Nous voulons que le chemin apparaisse dans le navigateur sous la forme http://my-ruby-garage.com/create-a-car et que nous puissions référencer cette route à l’intérieur de notre application sous la forme create_car. Il existe un module Wizard::Car qui connaît chaque étape de l’assistant.

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

Le code ci-dessus crée le même motif pour chaque étape. Par exemple, l’étape1 est accessible dans le navigateur via l’URL http://my-ruby-garage.com/create-a-car/step1, son formulaire correspondant soumet une requête post à http://my-ruby-garage.com/create-a-car/validate-step, et le chemin peut être convoqué en appelant create_car_step1_path.

Route Redirects

Rails nous permet également de faire des redirections directement dans routes.rb. Dans l’exemple précédent, peut-être que je veux que toute personne atterrissant sur http://my-ruby-garage.com/create-a-car soit automatiquement redirigée vers la première étape. Cela peut être accompli avec le code suivant:

get 'create-a-car', 
to: redirect("/create-a-car/#{Wizard::SpotAccount::STEPS.first}")

Route Defaults

Vous pouvez définir des paramètres par défaut dans une route en passant un hash pour l’option :defaults.

resources :cars do
collection do
get :export, defaults: { format: 'csv' }
end
end

En utilisant ceci, la visite de http://my-ruby-garage.com/cars/export appellera l’action d’exportation dans le contrôleur de voitures et l’action de contrôleur correspondante répondra avec un csv par défaut.

Route Globbing

En utilisant des segments joker (fragments préfixés par une étoile), nous pouvons spécifier que les parties restantes d’une route doivent correspondre à un paramètre particulier. Ceci est appelé route globbing.

get '/rent/*slugs', to: 'cars#index', as: :rent_cars

Cette route correspondrait à http://my-ruby-garage.com/rent/lisbon/suv-sedan et définirait les paramètres à « lisbon/suv-sedan ». Cela pourrait ensuite être utilisé dans un système de recherche ou de filtrage contre notre base de données pour trouver des voitures à Lisbonne du type suv ou sedan.

J’écris une gem Slugcatcher avec cette fonctionnalité à l’esprit afin de marquer les modèles Rails qui peuvent être recherchés comme des route slugs.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.