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.
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 :id
d’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.