Conventions de routage de base
Examinons nos routes telles qu’elles sont maintenant, en utilisant rake routes
:
$ rake routes Prefix Verb URI Pattern Controller#Action list_posts GET /list_posts(.:format) application#list_posts GET /show_post/:id(.:format) application#show_post new_post GET /new_post(.:format) application#new_post create_post POST /create_post(.:format) application#create_post GET /edit_post/:id(.:format) application#edit_post POST /update_post/:id(.:format) application#update_post POST /delete_post/:id(.:format) application#delete_post POST /create_comment_for_post/:post_id(.:format) application#create_comment POST /list_posts/:post_id/delete_comment/:comment_id(.:format) application#delete_comment list_comments GET /list_comments(.:format) application#list_comments
L’une des informations clés des conventions Rails est que les applications centrées sur les données (ou les applications CRUDy) ont tendance à avoir des moyens très similaires pour permettre aux utilisateurs d’interagir avec l’application, qui sont:
- une page pour afficher une liste de quelque chose
- afficher quelque chose
- afficher un formulaire pour créer une nouvelle instance de quelque chose
- créer réellement quelque chose
- afficher un formulaire pour modifier une instance de quelque chose
- mettre à jour réellement quelque chose
- supprimer quelque chose
Ces sept « modèles d’interaction » sont si courants que Rails fournit un ensemble solide de conventions allant du routage aux contrôleurs, aux vues et aux formulaires pour simplifier ces flux de travail. Nous allons nous concentrer sur la partie routage maintenant.
Pour le routage, la convention est qu’au lieu de nous devoir trouver les modèles d’URL, Rails nous recommande de structurer les URL et les actions de contrôleur correspondantes de la manière suivante:
Flux de travail | VERBE HTTP | CHEMIN | Action du contrôleur |
---|---|---|---|
Afficher une liste de messages | GET | / messages | messages #index |
Afficher un article | OBTENIR | / messages/:id | messages # afficher |
Afficher la page pour créer un article | GET | /posts/new | posts #new |
Créer un message | MESSAGE | / messages | messages # créer |
Afficher la page pour modifier un article | GET | /posts/:id/edit | posts #edit |
Mettre à jour un article | PUT/PATCH | /posts/:id | posts #update |
Supprimer un message | SUPPRIMER | / messages/:id | messages #détruire |
Nous pouvons changer la partie post
de notre routage actuel pour suivre cette convention:
# posts GET /list_posts -> GET /posts posts#index GET /show_post/:id -> GET /posts/:id posts#show GET /new_post -> GET /posts/new posts#new POST /create_post -> POST /posts posts#create GET /edit_post/:id -> GET /posts/:id/edit posts#edit POST /update_post/:id -> PUT/PATCH /posts/:id posts#update POST /delete_post/:id -> DELETE /posts/:id posts#destroy
Et dans le fichier routes.rb
,
Rails.application.routes.draw do ### posts ### get '/posts' => 'posts#index' get '/posts/new' => 'posts#new' get '/posts/:id' => 'posts#show' post '/posts' => 'posts#create' get '/posts/:id/edit' => 'posts#edit' patch '/posts/:id' => 'posts#update' put '/posts/:id' => 'posts#update' delete '/posts/:id' => 'posts#destroy' # comments later.. ... end
Notez qu’avec ce nouveau modèle, il y a beaucoup moins de verbes dans l’URL elle-même, mais nous nous appuyons sur les verbes HTTP (GET
/POST
/PUT
/PATCH
/DELETE
) pour fournir la sémantique pour les autres modèles d’URL identiques, par exemple /posts/:id
.
Notez que PUT
avait été utilisé pour la mise à jour des ressources jusqu’à récemment, lorsque PATCH
a été déterminé comme une meilleure correspondance sémantique pour cette action. Depuis lors, Rails a préféré PATCH
, mais en autorisant les deux verbes pour les mises à jour.
Un autre changement que nous verrons plus tard est que nous acheminerons toutes les URL liées aux publications vers un PostsController
au lieu de tout gérer en ApplicationController
. Les noms d’action de PostController
- new
- index
- show
- create
- edit
- update
- destroy
sont également des conventions correspondant à l’interaction 7 motifs.
C’est l’ensemble de conventions le plus puissant que Rails vous impose en tant que développeur d’applications. Nous vous demanderons de faire un effort pour le mémoriser. Nous reviendrons sur cela de nombreuses fois tout au long du livre pour vous aider à le faire également.
Routage Pour plusieurs ressources
Souvent, nous avons besoin de plusieurs ressources présentes dans l’URL. Par exemple, pour notre application de blog chaque fois que nous avons besoin d’un itinéraire pour créer un commentaire, il est très important que nous sachions sur quel article ce commentaire est créé.
Nous sommes en train de le faire:
post 'create_comment_for_post/:post_id' => 'application#create_comment'
La convention Rails d’une URL avec plusieurs ressources associées consiste à commencer par la ressource « contenant » jusqu’à la ressource « la plus interne ». Par exemple, nos itinéraires pour les commentaires changeraient en:
post '/posts/:id/comments' => 'comments#create' delete '/posts/:post_id/comments/:id' => 'comments#destroy' get '/comments' => 'comments#index'
La sémantique de ces URL représente: « Créer un commentaire sous un message spécifique » et « supprimer un commentaire sous un message spécifique ». La dernière route, « afficher tous les commentaires dans le système », n’a pas besoin d’être « étendue » sous un message, donc l’URL n’a pas à mener avec « /messages ».
Si nous devons avoir plusieurs ressources dans l’URL avec leurs IDENTIFIANTS, la convention est telle que la dernière ressource utilisera l’espace réservé :id
et tout le reste sera :resource_id
tel que :post_id
.
Restful
REST signifie « Transfert d’État représentatif ». C’est un style d’architecture logicielle et une ligne directrice pour créer des services Web évolutifs. REST, en tant que moyen de structurer les applications Web, a de nombreuses facettes, mais regardons simplement comment cela s’applique à l’interface que nous utilisons pour interagir avec les applications Web, les URL.
Pour voir comment REST simplifie la sémantique des URL, parcourons un exemple. Disons que nous construisons un service de commande de pizzas en ligne. Une implémentation naïve des interfaces du service (URLs) serait:
/check_order?order_id=2 /place_new_order /pizza_details?type=1 /pay_for_my_order?order_id=12 /cancel_order?order_id=3 /expedite_order?order_id=13
Une conception d’interface RESTful ressemblerait à ceci:
GET /orders/2 POST /orders GET /pizzas/1 POST /orders/12/payments DELETE /orders/3 POST /orders/13/expeditions
Vous pouvez voir que les interfaces RESTful sont centrées sur des « noms » ou des « ressources », en supprimant les « verbes » des interfaces mais en s’appuyant sur les verbes HTTP standardisés (GET
/POST
/PUT
/DELETE
) pour fournir la sémantique CRUD pour les actions. Verbes tels que check
, place
, cancel
sont mappés directement aux verbes HTTP de GET
pour récupérer, POST
pour créer et DELETE
pour détruire la ressource order
. pay
et expedite
sont structurés comme création (HTTP POST) de sous-ressources de payments
et expeditions
sous ressource orders
.
Interfaces RESTful modèles d’interaction d’applications Web standardisés pour les rendre plus faciles à comprendre et à programmer. Parce que les interfaces sont centrées sur la manipulation des ressources, les réponses sont beaucoup plus prévisibles. Une analogie de la façon dont le modèle d’architecture RESTful simplifie l’interaction avec les services Web serait la façon dont la base de données relationnelle et le langage SQL simplifient le stockage de données. Avant la base de données relationnelle et SQL, les données étaient généralement stockées dans des systèmes propriétaires avec une logique spécifique pour interagir avec eux, ce qui signifiait que sur chaque projet, vous deviez apprendre un ensemble d’instructions différent pour interagir avec les données. Les bases de données relationnelles et SQL ont donné une structure de données commune (enregistrements de données sous forme de lignes et de colonnes stockées dans des tables) et un ensemble d’interfaces communes – quatre verbes simples de SELECT
, INSERT
, UPDATE
et DELETE
qui peut prendre en charge tous les types d’applications.
L’adoption d’une interface RESTful pour votre application Web rationalisera également votre application pour l’aligner sur la façon dont les données backend sont stockées dans les bases de données, et facilitera le développement. Nous verrons cela dans les chapitres suivants.
Notation des ressources
Nous avons parlé des conventions de routage de Rails et des modèles d’URL RESTful. Maintenant, notre fichier routes.rb
ressemblerait à ce qui suit:
### config/routes.rb ### Rails.application.routes.draw do ### posts ### get '/posts' => 'posts#index' get '/posts/new' => 'posts#new' get '/posts/:id' => 'posts#show' post '/posts' => 'posts#create' get '/posts/:id/edit' => 'posts#edit' patch '/posts/:id' => 'posts#update' put '/posts/:id' => 'posts#update' delete '/posts/:id' => 'posts#destroy' ### comments ### get '/comments' => 'comments#index' post '/posts/:id/comments' => 'comments#create' delete '/posts/:post_id/comments/:id' => 'comments#destroy' end
En fait, les routes comme ce que nous avons dans la section posts
sont très courantes, donc Rails fournit une notation spéciale resources
qui aide à les générer pour vous.
Nous pouvons simplement faire:
resources :posts
Cette ligne générera automatiquement les 8 lignes que nous avions auparavant. Notez que pour l’action update
, Rails autorise les verbes PUT
et PATCH
, pour des raisons de compatibilité.
Vous pouvez exécuter bundle exec rake routes
dans votre environnement de ligne de commande pour vérifier qu’il génère exactement le même ensemble de routes.
Notez que cette ligne unique générera 8 routes. Dans notre cas, nous avons besoin de toutes les routes ici, mais si vous n’avez besoin que d’un sous-ensemble des routes, vous pouvez les définir plus explicitement comme:
resources :posts, only:
Cette ligne ci-dessus ne générerait que 3 itinéraires pour vous – tapez bundle exec rake routes
pour le vérifier.
Ressources imbriquées
Rails nous permet également d’imbriquer des ressources pour créer des modèles d’URL avec plusieurs ressources, voir ci-dessous:
### config/routes.rb ### Rails.application.routes.draw do resources :posts do resources :comments, only: end resources :comments, only: :index end
Exécutez bundle exec rake routes
et voyez la sortie – cela devrait être le même que ce que nous avions auparavant.
Assistants de chemin
Lorsque vous exécutez bundle exec rake routes
, notez la colonne Prefix
pour certaines de ces routes. Ceux-ci sont là pour nous aider à savoir comment utiliser les assistants de chemin fournis par Rails pour nos itinéraires. Nous pouvons utiliser ces préfixes suivis de _path
dans nos contrôleurs et vues pour créer facilement des chemins.
Par exemple:
posts_path # => '/posts' post_id = 123 post_comments_path(post_id) # => '/posts/123/comments'
Quel est l’avantage d’utiliser des assistants d’URL, plutôt que de coder en dur les chemins tels que /posts/123/comments
directement dans votre code? (par exemple, dans l’action de votre contrôleur?) La raison pour laquelle vous souhaitez utiliser des assistants de chemin est que si vous souhaitez modifier les modèles d’URL dans votre application, il est beaucoup plus facile d’utiliser les assistants d’URL pour renvoyer un chemin différent – regardons un exemple:
get '/register', to: 'users#new', as: 'register'
Lorsque nous ajoutons la clause « as » à cette route, si vous exécutez bundle exec rake routes
, vous verrez la colonne Prefix
avec register
, et vous pouvez utiliser register_path
pour obtenir /register
le chemin. Maintenant, si nous voulons changer le chemin en /login
, tout ce que nous avons à faire est simplement de:
get '/login', to: 'users#new', as: 'register'
Maintenant, notre register_path
nous donne /login
. Nous n’avons pas du tout à changer notre code dans l’application Rails.
Plus de conventions de routage
Avant de passer à autre chose, jetons un coup d’œil à quelques variantes de ce que nous avons déjà vu, ainsi qu’à d’autres fonctionnalités disponibles dans le routage des rails:
### config/routes.rb ### Rails.application.routes.draw do # pointing our homepage (root path) to posts#index root to: 'posts#index' # `match` & `via:` allow us to define one route and use several HTTP verbs # `as:` lets us define the name of the route prefix match '/authors/:id' => 'authors#update', via: , as: :update_author # update_author PUT|PATCH /authors/:id(.:format) authors#update resources :posts do # define extra params to pass for requests to a route get 'popular', on: :collection, action: :index, popular: true # popular_posts GET /posts/popular(.:format) posts#index {:popular=>true} get 'preview', on: :member # ... end # we can even use routes to redirect get '/home', to: redirect('/') end
Décomposons toutes les fonctionnalités énumérées ci-dessus une à la fois.
-
root:
root
est utilisé pour spécifier quelle action correspond à « / » (l’URL de premier niveau de notre site qui n’a pas de chemin).L’URL racine de votre site Web / application est la plus couramment utilisée, à cause de celaroot
doit être spécifié en haut du fichier routes. -
match + via:
match
est utilisé pour faire correspondre les modèles d’URL à une ou plusieurs routes. Nous pouvons également spécifier quel verbe HTTP peut être utilisé pour faire correspondre une URL avec ce modèle. Nous le faisons en passant un hachage à la méthodematch
. La clé de ce hachage estvia
, et la valeur est un tableau de verbes HTTP.match
est une forme plus générale de certaines méthodes de routage HTTP plus couramment utilisées, telles queget
,post
etdelete
. Cela peut prendre toutes les mêmes options que ces méthodes, mais, par rapport à ces méthodes, cela donne un peu plus de flexibilité.
Par exemple, en utilisantmatch
, nous pouvons spécifier une URL qui correspond à deux routes différentes, chacune correspondant à deux verbes HTTP différents. Normalement, cela nécessiterait deux commandes, au lieu d’une. Nous pouvons le voir dans notre exemple ci-dessus, où nous associons le modèle d’URL'/authors/:id'
à l’action'authors#update'
. Nous spécifions ensuite quels verbes HTTP peuvent être utilisés pour émettre la requête pour cette URL avecvia:
. Spécifiez toujours une méthode HTTP lorsque vous utilisezmatch
, ne pas le faire peut avoir des implications négatives sur la sécurité de votre application.
match
présente une autre option de routage vers certaines actions dans Rails. En général, il est préférable de s’en tenir aux méthodesHttpHelpers
les plus couramment utilisées, telles queget
etpost
. -
as: Nous avons mentionné un peu plus tôt que l’option
as:
peut être utilisée avec notre déclaration de route pour changer le préfixe de nos assistants d’URL. Cela peut être utilisé de différentes manières. Nous pouvons utiliseras:
pour que nos assistants d’URL correspondent mieux aux URL personnalisées. Une autre utilisation consiste à changer l’assistant de chemin d’URL actuel en quelque chose de plus intuitif ou qui correspond mieux aux ressources d’une application. -
itinéraire de collecte : Voyez comment nous imbriquons notre itinéraire
/popular
sous la ressourceposts
. Nous utilisons ensuiteon: :collection
pour spécifier la partie d’une ressource sous laquelle nous imbriquons cette route. Nous avons beaucoup de messages, ce qui est considéré comme une collection. En spécifianton: :collection
, nous disons: « Faites correspondre une URL avec le chemin/posts/popular
. »Si nous n’ajoutons pason: :collection
, Rails supposera que cette route correspond à une autre ressource associée à un seul membre de notre collection de messages. Dans ce cas, notre itinéraire deviendrait/posts/:id/popular
. Nous pouvons également spécifier plusieurs routes de collecte en utilisant un format de bloc.
collection do get 'popular' end
- passer un paramètre supplémentaire: Nous pouvons spécifier un paramètre par défaut qui est toujours transmis avec notre hachage
params
lorsque nous sommes mis en correspondance avec certaines URL. Il y a deux façons de spécifier cela; une façon est la même que nous le faisons ci-dessus:
get 'popular', on: :collection, action: :index, popular: true
popular: true
sera transmis à notre action avec laquelle la route populaire correspond via le hachage params
. Il aura une clé de :popular
et une valeur de true
. Nous pouvons également utiliser une syntaxe plus explicite en passant un hachage à notre méthode de route get
, où la clé est defaults:
et la valeur est un autre hachage contenant le nom du paramètre que nous voulons transmettre à notre action.
get 'popular', on: :collection, action: :index, defaults: { popular: true}
-
route membre : Nous pouvons utiliser
on: member
pour spécifier que notre route correspond à un membre d’une collection. Si nous l’utilisons, le segment dynamique apparaîtra sous la forme:id
. Un assistant d’URL sera également créé en tant quepreview_post
. En spécifiant cette route avecon: member
, nous indiquons à Rails qu’il s’agit d’un membre de cette ressource particulière. Qu’il ne s’agit pas simplement d’une autre ressource imbriquée sous les publications, mais plus étroitement liée ou liée à nos publications dans cette application. Plusieurs routes membres peuvent être définies à l’aide d’un format de bloc ; ce format utilise la même syntaxe que le format de bloc pour définir plusieurs routes de collection, il suffit de remplacercollection
parmember
. -
redirection: Il y a un autre concept dont il faut parler qui est affiché dans notre exemple ci-dessus, et c’est la redirection. Rails nous donne la possibilité de rediriger d’un chemin vers un autre en utilisant un assistant de redirection en conjonction avec une route.
get '/home', to: redirect('/')
. Si quelqu’un tente d’accéder au chemin/home
, il sera immédiatement redirigé vers le chemin racine/
. Ce n’est pas limité à un seul chemin d’URL bien sûr; nous pourrions aussi avoir quelque chose comme ceci:get '/home', to: redirect('/travel')
.
Examen
Les itinéraires de rails se trouvent à l’avant d’une application. Une route interprète une requête HTTP entrante et:
- fait correspondre une requête à une action de contrôleur sur la base de la combinaison d’un verbe HTTP et du modèle d’URL de requête
- capture des données dans l’URL pour qu’elles soient disponibles dans
params
dans les actions de contrôleur - Rails encourage les développeurs à utiliser des modèles d’URL RESTful lors de la configuration des routes, avec une conceptualisation de la manipulation des ressources avec des verbes HTTP.
- Vous pouvez utiliser la macro
resources
pour générer très rapidement des routes RESTful.