On The Rails Again

Le routage de ressources en Rails

Posté par Nicolas le 01 novembre 2011

Le routage de ressources en Rails permet de déclarer très rapidement l'ensemble des routes pour un contrôleur qui respecte l'architecture REST. Cet article présente comment définir les routes pour des ressources.

Pré-requis :
Ce que nous allons voir :
  • Un rappel sur REST
  • Définir des routes pour des ressources
  • Ajouter des routes pour des actions spécifiques aux ressources

Rappel sur les ressources et sur REST

Notion de ressource

La notion de ressource est vague et donc de difficile à définir. Prenons la première définition explicite du terme ressource dans son sens le plus général donnée par Tim berners Lee  :

Une ressource peut être toute chose qui possède une identité. Des exemples familiers incluent un document électronique, une image, un service (par exemple "le bulletin météo d'aujourd'hui pour Los Angeles"), ou un ensemble d'autres ressources. Certaines ressources ne peuvent pas être "ramenées par le réseau" (network retrievable), par exemple les êtres humains, les entreprises, les livres d'une bibliothèque peuvent être aussi considérés comme des ressources.

Ce qu'il est important de comprendre c'est qu'une ressource est finalement n'importe quoi que l'on peut identifier de manière unique par une URI (Uniform Resource Identifier). Sur le web, cet identifiant unique est généralement une URL.

Même si cette notion paraît difficile à appréhender aux premiers abords, elle vous paraîtra plus claire une fois utilisée dans une application. Passons donc à la suite et à une approche de l'architecture REST.

Notion de REST

REST est un style architectural, une manière de construire une application pour le web. Les principes essentiels d'une architecture REST sont les suivants :

  • Chaque ressource doit être identifiée de manière unique par une URI.
  • Les méthodes HTTP GET, POST, PUT et DELETE suffisent pour accéder à et modifier une ressource.

Exemple d'application RESTful

Je pense qu'il n'y a pas plus parlant qu'un exemple pour comprendre ce qu'est l'architecture REST et ce qu'est une ressource.
Prenons donc l'exemple d'un blog contenant plusieurs articles. Ici, les ressources à manipuler sont les articles. Dans ce blog on peut ajouter, modifier, lire, et supprimer des articles. Chaque article a un identifiant unique, ici c'est son nom. Donc, pour que l'application respecte l'architecture REST elle doit permettre les actions suivantes :

  • Lire un article - on effectue une requête de type GET sur http://monblog.fr/articles/nom-de-mon-article. Le nom de l'article étant son identifiant unique.
  • Écrire un article - on effectue une requête de type POST sur http://monblog.fr/articles/. Le contenu du message POST représentant le contenu du nouvel article à créer.
  • Modifier un article - on effectue une requête de type PUT sur http://monblog.fr/articles/nom-de-mon-article. Le contenu du message PUT représentant le contenu modifié de l'article.
  • Supprimer un article - on effectue une requête de type DELETE sur http://monblog.fr/articles/nom-de-mon-article.

Si vous avez besoin de plus d'informations au sujet de REST reportez vous à la section REST de l'article Avant de commencer avec Ruby On Rails

Les routes pour des ressources

CRUD, méthodes HTTP et actions

En Rails, le routage de ressources fournit une correspondance entre les verbes HTTP et les URLs avec les actions du contrôleur. Par convention, chaque action du contrôleur correspond à une opération CRUD (create, read, update, destroy) dans la base de données.

Prenons un exemple, supposons que nous avons un blog contenant des articles qui sont ici les ressources à manipuler. Voici comment définir les routes pour ce type de ressources :

# config/routes.rb
resources :articles

Cette seule règle permet de définir les routes pour les actions index, show, new, edit, create, update et destroy, qui sont les actions typiques que l'on doit pouvoir effectuer sur une ressource.

Nous obtenons les sept routes suivantes qui s'appliquent toutes au contrôleur articles_controller :

Méthode
HTTP
URL Action Utilité
GET /articles index Afficher la liste de tous les articles
GET /articles/new new Afficher un formulaire pour créer un article
POST /articles create Créer un nouvel article à partir du contenu du message POST
GET /articles/:id show Afficher l'article ayant pour id celle passée dans l'URL
GET /articles/:id/edit edit Afficher un formulaire pour editer l'article ayant pour id celle passée dans l'URL
PUT /articles/:id update Mettre à jour un article ayant pour id celle passée dans l'URL à partir du corps du message PUT
DELETE /articles/:id destroy Supprimer l'article ayant pour id celle passée dans l'URL

Il est important de savoir qu'il y a une priorité sur les règles. Les règles écrites au début du fichier sont prioritaires par rapport à celles écrites en dessous.

Chemins et URLs générés

Comme pour toutes les routes, le routage de ressources génère des chemins et des URLs. Voici un tableau récapitulatif de ces helpers et des actions vers lesquelles ils redirigent en fonction du verbe HTTP employé :

Path helper Méthode
HTTP
Action
articles_path GET index
POST create
article_path(:id) Ce path prend en paramètre l'id de l'article à modifier GET show
PUT update
DELETE destroy
new_article_path GET new
edit_article_path GET edit

Comme tous les routes helpers, il y a aussi les URLs helpers qui sont générés. Pour s'en servir, il suffit de remplacer …_path par …_url. Par exemple, new_article_url.

Exemple d'utilisations

Le routage de ressource est utilisé par Rails lorsque l'on crée un scaffold. Rails génère les routes, le modèle, la table en base de données, les actions RESTful dans le contrôleur et les vues. Donc pour voir un bon exemple des path_heplers, il suffit de regarder dans les vues générées.

Par exemple, si on crée le scaffold suivant :

$ rails generate scaffold Article title:string content:text

On peut constater l'utilisation des path_helpers suivants :

# app/views/articles/index.html.erb
...
<%= link_to 'New Article', new_article_path %>
...
# app/views/articles/show.html.erb
...
# Ici @article est défini dans la méthode show du contrôleur articles_controller
<%= link_to 'Edit', edit_article_path(@article) %> |
<%= link_to 'Back', articles_path %>
...
# app/views/articles/show.html.erb
...
# Ici @article est défini dans la méthode edit du contrôleur articles_controller
<%= link_to 'Show', @article %> |
<%= link_to 'Back', articles_path %>
...

Pour le dernier exemple, on peut voir que le lien pour l'action show n'utilise pas le path_helper article_path(@article). Ceci est dû au fait que Rails comprend tout seul que lorsqu'on lui passe directement une instance de l'objet Article il doit utiliser le path_helper article_path et donc on fonction de la méthode HTTP utilisé il redirigera vers la bonne action du contrôleur. Ici c'est un lien donc c'est la méthode GET qui est utilisé et donc ce lien redirigera vers l'action show.

Définir plusieurs ressources

Le routeur Rails nous permet de définir plusieurs ressources en une seule ligne de la façon suivante :

resources :articles, :photos, :authors

Les routes pour une ressource unique

CRUD, méthodes HTTP et actions

Il peut arriver que l'on ait besoin de définir les routes pour une ressource unique à laquelle on aimerait accéder sans préciser une ID. Le routeur Rails nous permet de définir ce genre de route. Prenons un exemple pour voir l'ensemble des routes créées.

# config/routes.rb
resource :account

Faire attention, dans ce cas il n'y a pas de « s » au mot resource

Cette seule règle permet de définir les routes pour les actions show, new, edit, create, update et destroy du contrôleur accounts_controller. Voici un récapitulatif :

Méthode
HTTP
URL Action Utilité
GET /account/new new Afficher un formulaire pour créer un compte
POST /account create Créer le nouveau compte à partir du contenu du message POST
GET /account show Afficher le seul et unique compte
GET /account/edit edit Afficher un formulaire pour editer le compte
PUT /account update Mettre à jour le seul et unique compte à partir du contenu du message PUT
DELETE /account destroy Supprimer le compte

Chemins et URLs générés

Dans la ces d'une ressource unique, les path_helpers générés ne prennent pas de paramètre étant donné que la ressource à modifier est toujours la même. Voici un tableau récapitulatif de ces helpers et des actions vers lesquelles ils redirigent en fonction du verbe HTTP employé :

Path helper Méthode
HTTP
Action
account_path GET show
POST create
PUT update
DELETE destroy
new_account_path GET new
edit_account_path GET edit

Ajouter des actions RESTful

Il arrive souvent que l'on ait besoin d'ajouter des routes à une ressource pour des actions autres que celles définies par défaut. Le routeur Rails nous permet de le faire très simplement, voyons comment.

Ajout d'une action sur la collection

Tout d'abord, il faut définir si cette action va agir sur l'ensemble des ressources ou seulement sur une seule. Prenons un exemple, supposons que l'on ait un contrôleur photos_controller et que l'on veuille ajouter la possiblité de faire une recherche sur les photos. Dans ce cas, l'action sera effectuée sur l'ensemble des ressources photos. Donc on défini les routes comme ceci :

resources :photos do
  get 'search', :on => :collection
end

Il est possible d'utiliser des symboles à la place des chaînes de caractères. Par exemple, on pourrait écrire :
get :search, :on => :collection

Ajout d'une action sur un membre

Supposons maintenant que l'on veuille effectuer une action sur une seule ressource, par exemple accéder à une previsualisation d'une photo. Dans ce cas on peux définir les routes comme ceci :

resources :photos do
  get 'preview', :on => :member 
end

Les routes helpers obtenus dans les deux cas précédents sont respectivement search_photos_path et preview_photo_path. Bien faire attention au « s » à la fin de photos que l'on met que lorsque l'action est sur la collection entière.

Si on a beaucoup d'actions à ajouter sur les membres ou sur la collection entière on peut également définir les routes comme ceci :

resources :photos do
  member do
    get 'preview'
    get 'buy'
  end
  collection do
    get 'search'
    get 'another_action'
  end
end

Il faut noter ici que l'on peut remplacer let mot get par les autres méthodes HTTP, par exemple post

Voilà les bases pour le routage de ressources en Rails, je publierai prochainement un article sur les ressources imbriquées. Si vous avez des questions ou améliorations à proposer n'hésitez pas à laissez un commentaire.

Références