Maîtriser Ruby on Rails : Développement Web Rapide et Efficace
Maîtriser Ruby on Rails : Développement Web Rapide et Efficace

Routing et Contrôleurs : Gérer les Requêtes et les Réponses

Introduction : Le Cœur de l'Interaction Web avec Rails

Dans le monde du développement web, chaque interaction commence par une requête envoyée par un navigateur (ou un autre client) vers un serveur, et se termine par une réponse renvoyée par le serveur au client. Pour un framework comme Ruby on Rails, orchestrer ce flux de requêtes et de réponses est une tâche fondamentale. C'est précisément le rôle du Routing et des Contrôleurs.

Le Routing (ou routage) agit comme le GPS de votre application. Il prend l'URL de la requête entrante et la "traduit" en une destination spécifique au sein de votre application. Cette destination est généralement une action à exécuter par un Contrôleur.

Les Contrôleurs, quant à eux, sont les chefs d'orchestre. Ils reçoivent la demande du routeur, interagissent avec les modèles (pour accéder aux données) et les vues (pour générer l'affichage), puis préparent la réponse appropriée à renvoyer au client.

Ensemble, le routing et les contrôleurs forment la colonne vertébrale de la manière dont votre application Rails interagit avec le monde extérieur. Comprendre leur fonctionnement est essentiel pour construire des applications web robustes, maintenables et performantes.

I. Le Routing dans Rails : Le GPS de votre Application

1. Qu'est-ce que le Routing ?

Le routing est le processus de mapper les requêtes HTTP entrantes (basées sur leur URL et leur verbe HTTP) aux actions spécifiques des contrôleurs. C'est la première étape du cycle de vie d'une requête dans Rails.

Toutes les définitions de routes sont centralisées dans le fichier config/routes.rb. Ce fichier est une Domain Specific Language (DSL) propre à Rails, ce qui rend la définition des routes très intuitive et expressive.

2. Les Verbes HTTP et les Routes Simples

Les requêtes HTTP utilisent différents verbes (méthodes) pour indiquer le type d'opération souhaitée. Rails utilise ces verbes pour distinguer les routes et les actions. Les plus courants sont :

  • GET: Récupérer une ressource (ex: afficher une page, une liste d'articles).
  • POST: Créer une nouvelle ressource (ex: soumettre un formulaire de création).
  • PUT/PATCH: Mettre à jour une ressource existante (ex: soumettre un formulaire de modification).
  • DELETE: Supprimer une ressource.

Voici comment définir des routes simples dans config/routes.rb :

# config/routes.rb

Rails.application.routes.draw do
  # Route GET : Quand une requête GET arrive sur '/pages/about',
  # elle est dirigée vers l'action 'about' du 'PagesController'.
  get '/pages/about', to: 'pages#about'

  # Route POST : Quand une requête POST arrive sur '/articles',
  # elle est dirigée vers l'action 'create' du 'ArticlesController'.
  post '/articles', to: 'articles#create'

  # Route racine (Root Route) : L'URL par défaut de votre application (ex: votre-domaine.com/)
  root 'welcome#index'
end

3. Les Routes Resources (CRUD) : La Convention Rails

Rails favorise la convention plutôt que la configuration. Les routes resources en sont un excellent exemple. Elles vous permettent de déclarer un ensemble complet de routes RESTful pour une ressource donnée (comme des articles, des utilisateurs, etc.) en une seule ligne de code.

# config/routes.rb

Rails.application.routes.draw do
  resources :articles
  resources :users
end

La ligne resources :articles génère automatiquement 7 routes différentes, couvrant les opérations CRUD (Create, Read, Update, Delete) pour la ressource Article :

| Verbe HTTP | URI Pattern | Nom du chemin (Prefix) | Action du Contrôleur | Description | | :--------- | :------------------ | :----------------------- | :------------------- | :--------------------------------------- | | GET | /articles | articles_path | articles#index | Affiche la liste de tous les articles. | | GET | /articles/:id | article_path(id) | articles#show | Affiche un article spécifique. | | GET | /articles/new | new_article_path | articles#new | Affiche le formulaire pour un nouvel article. | | POST | /articles | articles_path | articles#create | Crée un nouvel article. | | GET | /articles/:id/edit| edit_article_path(id) | articles#edit | Affiche le formulaire pour modifier un article. | | PATCH/PUT| /articles/:id | article_path(id) | articles#update | Met à jour un article spécifique. | | DELETE | /articles/:id | article_path(id) | article_path(id) | Supprime un article spécifique. |

Options Utiles pour resources :

  • only: Pour ne générer qu'un sous-ensemble des routes. Ex: resources :articles, only: [:index, :show]
  • except: Pour exclure certaines routes. Ex: resources :articles, except: [:destroy]
  • member: Ajoute des routes pour une ressource spécifique (/articles/:id/mon_action).
    resources :articles do
      member do
        get 'preview' # => GET /articles/:id/preview
      end
    end
    
  • collection: Ajoute des routes pour la collection de ressources (/articles/mon_action).
    resources :articles do
      collection do
        get 'search' # => GET /articles/search
      end
    end
    
  • nested resources (Ressources imbriquées) : Utile pour les relations parent-enfant.
    resources :articles do
      resources :comments # => /articles/:article_id/comments
    end
    

4. Générer des URLs (Helpers de Route)

Rails génère automatiquement des helpers de route pour chaque route nommée (celle avec un Prefix). Ces helpers sont des méthodes Ruby qui vous permettent de générer les URLs correspondantes, ce qui rend votre code plus robuste et facile à maintenir.

  • articles_path génère /articles
  • new_article_path génère /articles/new
  • article_path(@article) (où @article est une instance d'Article avec un id) génère /articles/1 (si @article.id est 1)
  • edit_article_path(@article) génère /articles/1/edit

Il existe aussi des versions _url (ex: articles_url) qui incluent le protocole et le nom de domaine complet (http://localhost:3000/articles).

Pourquoi utiliser les helpers ? Si vous décidez de changer l'URL d'une route, vous n'avez qu'à la modifier dans config/routes.rb. Tous les helpers de route s'adapteront automatiquement, évitant ainsi les erreurs de liens brisés.

5. Inspecter les Routes

Pour voir toutes les routes définies dans votre application, utilisez la commande Rails :

rails routes

Cette commande affiche un tableau détaillé de toutes les routes, leurs verbes HTTP, leurs URIs, les actions de contrôleur correspondantes et leurs helpers de route. C'est un outil indispensable pour le débogage et la compréhension du routing.

II. Les Contrôleurs dans Rails : Les Chefs d'Orchestre

1. Qu'est-ce qu'un Contrôleur ?

Un Contrôleur (Controller) est la couche intermédiaire dans l'architecture MVC (Model-View-Controller) de Rails. Son rôle est de :

  1. Recevoir les requêtes : Interpréter les paramètres de la requête HTTP.
  2. Interagir avec le Modèle : Accéder, créer, modifier ou supprimer des données via les modèles (qui représentent votre base de données).
  3. Interagir avec la Vue : Préparer les données pour l'affichage et choisir la vue appropriée pour générer la réponse HTML.
  4. Préparer la Réponse : Renvoyer une réponse HTTP au client (HTML, JSON, redirection, etc.).

Chaque contrôleur est une classe Ruby qui hérite de ApplicationController, lequel lui-même hérite de ActionController::Base. Les actions d'un contrôleur sont simplement des méthodes publiques définies dans cette classe.

2. Anatomie d'un Contrôleur

Les contrôleurs sont situés dans le dossier app/controllers/. Par convention, un contrôleur pour une ressource Article se nommerait ArticlesController et serait défini dans app/controllers/articles_controller.rb.

# app/controllers/articles_controller.rb

class ArticlesController < ApplicationController
  # Une action 'index' pour afficher tous les articles
  def index
    @articles = Article.all # Récupère tous les articles du modèle
    # Rails va par défaut chercher le template 'app/views/articles/index.html.erb'
  end

  # Une action 'show' pour afficher un article spécifique
  def show
    @article = Article.find(params[:id]) # Récupère l'article par son ID
    # Rails va par défaut chercher le template 'app/views/articles/show.html.erb'
  end

  # Une action 'new' pour afficher le formulaire de création d'un nouvel article
  def new
    @article = Article.new # Crée une nouvelle instance vide d'Article
    # Rails va par défaut chercher le template 'app/views/articles/new.html.erb'
  end

  # Une action 'create' pour traiter la soumission du formulaire de création
  def create
    @article = Article.new(article_params) # Crée l'article avec les paramètres du formulaire

    if @article.save # Tente de sauvegarder l'article en base de données
      redirect_to @article, notice: 'Article créé avec succès.' # Redirige vers l'article créé
    else
      render :new # Affiche à nouveau le formulaire 'new' avec les erreurs de validation
    end
  end

  # ... et d'autres actions comme edit, update, destroy

  private

  # Méthode privée pour la sécurité des paramètres (Strong Parameters)
  def article_params
    params.require(:article).permit(:title, :content)
  end
end

3. Le Flux de Requête/Réponse dans le Contrôleur

Lorsqu'une requête arrive et est routée vers une action de contrôleur :

  1. L'action est exécutée : Le code à l'intérieur de la méthode d'action est exécuté. C'est ici que vous interagissez avec les modèles (Article.all, Article.find, @article.save).
  2. Préparation de la réponse :
    • Rendu d'une vue : Par défaut, Rails cherche un fichier de vue correspondant à l'action et au contrôleur (ex: app/views/articles/index.html.erb pour ArticlesController#index). Les variables d'instance (celles qui commencent par @) définies dans l'action sont disponibles dans la vue.
    • Redirection : redirect_to envoie une réponse HTTP 302 (Redirection) au navigateur, lui indiquant d'aller à une autre URL.
    • Rendu direct : render plain: "Hello" ou render json: @data permet de renvoyer directement du texte ou du JSON sans passer par un fichier de vue ERB.

4. Les Paramètres de Requête (params)

Toutes les données envoyées avec une requête HTTP (à partir de l'URL, d'un formulaire, etc.) sont accessibles via le hash params dans le contrôleur.

  • Pour /articles/1, params[:id] serait 1.
  • Pour un formulaire avec <input name="article[title]" value="Mon Titre">, params[:article][:title] contiendrait "Mon Titre".

Strong Parameters : La Sécurité Avant Tout

Lorsqu'un utilisateur soumet un formulaire, il pourrait potentiellement envoyer des données malveillantes ou des champs non désirés (comme un admin: true si vous aviez un champ admin dans votre modèle User). Les Strong Parameters sont une fonctionnalité de sécurité essentielle de Rails qui vous oblige à explicitement lister les paramètres autorisés à être sauvegardés ou mis à jour dans votre base de données.

class ArticlesController < ApplicationController
  def create
    @article = Article.new(article_params) # Utilisation des strong parameters

    if @article.save
      redirect_to @article, notice: 'Article créé avec succès.'
    else
      render :new
    end
  end

  private

  # Méthode privée pour les strong parameters
  # Elle garantit que seuls les paramètres 'title' et 'content'
  # sous la clé 'article' sont acceptés.
  def article_params
    params.require(:article).permit(:title, :content, :category_id)
  end
end
  • params.require(:article): S'assure qu'une clé de haut niveau nommée article est présente dans les paramètres. Si elle est absente, une erreur est levée.
  • .permit(:title, :content, :category_id): N'autorise que les paramètres title, content et category_id à passer. Tous les autres paramètres sous la clé article seront ignorés.

5. Actions Courantes des Contrôleurs (Pattern CRUD)

Les 7 actions générées par resources :votre_ressource sont un standard dans Rails et suivent le pattern CRUD (Create, Read, Update, Delete) :

  • index: Afficher une collection de ressources.
  • show: Afficher une ressource spécifique.
  • new: Afficher un formulaire pour créer une nouvelle ressource.
  • create: Créer une nouvelle ressource à partir des données du formulaire.
  • edit: Afficher un formulaire pour modifier une ressource existante.
  • update: Mettre à jour une ressource existante à partir des données du formulaire.
  • destroy: Supprimer une ressource spécifique.

6. Les Filtres (Before/After Actions)

Rails permet de définir des filtres (ou callbacks) qui s'exécutent avant, après ou même autour des actions d'un contrôleur. before_action est le plus couramment utilisé. Il est parfait pour le code que vous souhaitez exécuter avant plusieurs actions, comme la récupération d'un objet par son ID.

# app/controllers/articles_controller.rb

class ArticlesController < ApplicationController
  # Avant d'exécuter les actions :show, :edit, :update ou :destroy,
  # appelle la méthode privée :set_article.
  before_action :set_article, only: [:show, :edit, :update, :destroy]

  def index
    @articles = Article.all
  end

  def show
    # @article est déjà défini par :set_article
  end

  def new
    @article = Article.new
  end

  def create
    @article = Article.new(article_params)
    if @article.save
      redirect_to @article, notice: 'Article créé avec succès.'
    else
      render :new
    end
  end

  def edit
    # @article est déjà défini par :set_article
  end

  def update
    if @article.update(article_params)
      redirect_to @article, notice: 'Article mis à jour avec succès.'
    else
      render :edit
    end
  end

  def destroy
    @article.destroy
    redirect_to articles_url, notice: 'Article supprimé avec succès.'
  end

  private

  def set_article
    @article = Article.find(params[:id])
  end

  def article_params
    params.require(:article).permit(:title, :content, :category_id)
  end
end

En utilisant before_action :set_article, vous évitez de répéter Article.find(params[:id]) dans les quatre actions, rendant le code plus DRY (Don't Repeat Yourself) et plus propre.

III. Interaction Routing et Contrôleurs : Le Cycle de Vie d'une Requête

Le processus complet du traitement d'une requête HTTP par Rails, impliquant le routing et les contrôleurs, peut être visualisé ainsi :

  1. Requête HTTP entrante : Le navigateur envoie une requête (ex: GET /articles/1).
  2. Serveur Web (Puma) : Reçoit la requête et la transmet à l'application Rails via Rack.
  3. Rails Router (config/routes.rb) : Examine l'URL et le verbe HTTP. Il trouve la route correspondante (GET /articles/:id mappée à articles#show).
  4. Dispatcher : Le router transmet la requête au contrôleur et à l'action identifiés (ArticlesController#show).
  5. Contrôleur (ArticlesController) :
    • Exécute les before_action (ex: set_article pour trouver l'article avec params[:id]).
    • Exécute l'action (show dans cet exemple), qui prépare les données (@article).
    • Décide de la réponse (par défaut, rendre la vue correspondante).
  6. Vue (app/views/articles/show.html.erb) : Utilise les variables d'instance du contrôleur (@article) pour générer le HTML final.
  7. Réponse HTTP : Le HTML généré est renvoyé au navigateur avec un code de statut HTTP (ex: 200 OK).
  8. Navigateur : Affiche la page HTML à l'utilisateur.

Ce cycle se répète pour chaque requête, et c'est la fluidité de cette interaction qui rend Rails si efficace pour le développement web.

IV. Exemples Pratiques

1. Un Blog Simple : Articles

Objectif : Créer des routes et un contrôleur pour gérer des articles de blog.

  1. Génération du contrôleur et du modèle (si vous partez de zéro) :

    rails generate scaffold Article title:string content:text category:references
    

    Cette commande génère le modèle Article, la migration, le contrôleur ArticlesController, les vues correspondantes et met à jour config/routes.rb avec resources :articles.

  2. config/routes.rb (automatiquement généré) :

    # config/routes.rb
    
    Rails.application.routes.draw do
      resources :articles # Génère toutes les routes CRUD pour les articles
      root 'articles#index' # Définit la page d'accueil comme la liste des articles
    end
    
  3. app/controllers/articles_controller.rb (extraits clés) :

    # app/controllers/articles_controller.rb
    
    class ArticlesController < ApplicationController
      before_action :set_article, only: %i[ show edit update destroy ]
    
      # GET /articles
      def index
        @articles = Article.all
      end
    
      # GET /articles/1
      def show
        # @article est défini par set_article
      end
    
      # GET /articles/new
      def new
        @article = Article.new
      end
    
      # POST /articles
      def create
        @article = Article.new(article_params)
    
        if @article.save
          redirect_to @article, notice: "Article créé avec succès."
        else
          render :new, status: :unprocessable_entity
        end
      end
    
      # PATCH/PUT /articles/1
      def update
        if @article.update(article_params)
          redirect_to @article, notice: "Article mis à jour avec succès."
        else
          render :edit, status: :unprocessable_entity
        end
      end
    
      # DELETE /articles/1
      def destroy
        @article.destroy
        redirect_to articles_url, notice: "Article supprimé."
      end
    
      private
        # Utilise des callbacks pour partager une logique commune entre les actions.
        def set_article
          @article = Article.find(params[:id])
        end
    
        # N'autorise qu'un sous-ensemble de paramètres ("strong parameters") via une liste blanche.
        def article_params
          params.require(:article).permit(:title, :content, :category_id)
        end
    end
    

Dans cet exemple, resources :articles dans routes.rb simplifie énormément la déclaration des chemins. Le ArticlesController implémente les actions CRUD standards, avec before_action pour DRYer la recherche d'articles et article_params pour garantir la sécurité des données soumises.

2. Route Personnalisée pour un Dashboard Admin

Objectif : Créer une route et une action pour un tableau de bord d'administration accessible à /admin_dashboard.

  1. Définition de la route dans config/routes.rb :

    # config/routes.rb
    
    Rails.application.routes.draw do
      # ... autres routes ...
    
      # Route personnalisée pour le tableau de bord d'administration
      get 'admin_dashboard', to: 'admin#dashboard', as: 'admin_dashboard'
    end
    
    • get 'admin_dashboard' : Définit le chemin d'accès pour les requêtes GET.
    • to: 'admin#dashboard' : Indique que la requête doit être traitée par l'action dashboard du AdminController.
    • as: 'admin_dashboard' : Crée un helper de route nommé admin_dashboard_path (et admin_dashboard_url) pour générer facilement ce lien.
  2. Création du AdminController :

    rails generate controller Admin dashboard
    

    Cette commande va créer app/controllers/admin_controller.rb et app/views/admin/dashboard.html.erb.

  3. app/controllers/admin_controller.rb :

    # app/controllers/admin_controller.rb
    
    class AdminController < ApplicationController
      # Vous pourriez ajouter un before_action ici pour l'authentification admin
      # before_action :authenticate_admin!
    
      def dashboard
        # Logique spécifique au tableau de bord, par exemple :
        @total_users = User.count
        @recent_articles = Article.order(created_at: :desc).limit(5)
        # La vue app/views/admin/dashboard.html.erb sera rendue par défaut
      end
    end
    

Ce scénario montre comment définir des routes plus spécifiques qui ne sont pas nécessairement des ressources complètes, mais des points d'entrée uniques pour des fonctionnalités particulières.

Conclusion : Les Fondations de Votre Application Rails

Le routing et les contrôleurs sont des piliers fondamentaux de toute application Ruby on Rails.

  • Le Routing est le système de navigation qui traduit les requêtes URL en instructions pour votre application. En utilisant resources et des routes personnalisées, vous définissez clairement les points d'entrée de votre application.
  • Les Contrôleurs sont les cerveaux opérationnels qui reçoivent ces instructions, coordonnent les interactions avec les modèles (données) et les vues (interface utilisateur), puis renvoient la réponse adéquate au client. La maîtrise des params, des strong parameters et des before_action est cruciale pour des contrôleurs efficaces et sécurisés.

En comprenant en profondeur comment ces deux composants interagissent, vous serez en mesure de concevoir des applications Rails bien structurées, faciles à maintenir et à faire évoluer, tout en respectant les conventions qui font la force du framework. Continuez à expérimenter avec rails routes et à déconstruire le cycle de vie de la requête pour solidifier vos connaissances.