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

Les Vues et les Formulaires : Création d'Interfaces Utilisateur Interactives

Introduction

Dans le cadre de notre exploration de Ruby on Rails, nous avons déjà abordé les bases de l'architecture MVC (Modèle-Vue-Contrôleur) et la manière dont les Modèles gèrent les données et les Contrôleurs orchestrent la logique métier. Il est maintenant temps de se concentrer sur l'interface utilisateur, la partie la plus visible de toute application web : les Vues et les Formulaires.

Les vues sont la vitrine de votre application ; elles sont responsables de la présentation des données à l'utilisateur. Les formulaires, quant à eux, sont le principal moyen par lequel les utilisateurs interagissent avec votre application, en saisissant des informations qui seront ensuite traitées par vos contrôleurs et enregistrées par vos modèles.

Comprendre et maîtriser la création de vues élégantes et de formulaires robustes est fondamental pour développer des applications Rails non seulement fonctionnelles, mais aussi intuitives et agréables à utiliser. Cette leçon vous guidera à travers les concepts clés et les meilleures pratiques pour bâtir des interfaces utilisateur interactives avec Rails.

I. Les Vues : La Présentation des Données

En Rails, les vues sont les fichiers .html.erb (ou d'autres extensions comme .html.haml, .html.slim si vous utilisez des préprocesseurs) qui contiennent le code HTML de votre application, agrémenté de code Ruby embarqué. C'est ici que les données préparées par vos contrôleurs prennent forme pour être affichées au navigateur de l'utilisateur.

1. Qu'est-ce qu'une Vue ?

Une Vue est la composante de l'architecture MVC responsable de l'affichage des données. Elle reçoit les informations du contrôleur et les formate en HTML, JSON, XML ou tout autre format que le client (généralement un navigateur web) peut comprendre.

  • Le "V" de MVC : La vue est la couche de présentation.
  • Fichiers .html.erb : Le format standard de Rails pour les vues. ERB signifie "Embedded Ruby", permettant d'insérer du code Ruby directement dans votre HTML.

2. Structure d'une Vue Rails

Les fichiers de vue résident généralement dans le répertoire app/views. Chaque action de contrôleur a généralement une vue correspondante (ex: app/views/users/index.html.erb pour l'action index du UsersController).

Le code Ruby dans une vue est délimité par des balises spéciales :

  • <% ... %> : Exécute le code Ruby mais n'affiche rien. Utilisé pour les boucles, les conditions, les affectations.
  • <%= ... %> : Exécute le code Ruby et affiche le résultat. Utilisé pour afficher du texte, des variables, des appels de méthodes.

Exemple de Vue simple (app/views/posts/show.html.erb) :

<h1><%= @post.title %></h1>
<p><%= @post.content %></p>

<p>
  <small>Créé le <%= @post.created_at.strftime("%d/%m/%Y à %Hh%M") %></small>
</p>

<%= link_to 'Modifier cet article', edit_post_path(@post) %> |
<%= link_to 'Retour aux articles', posts_path %>

Dans cet exemple, @post est une variable d'instance passée par le contrôleur. Les méthodes Ruby comme strftime sont utilisées pour formater la date. Les helpers Rails comme link_to génèrent des balises HTML <a>.

3. Les Gabarits (Layouts)

Rails utilise des gabarits (layouts) pour éviter la répétition de code HTML commun (comme l'en-tête, le pied de page, les barres de navigation). Le gabarit par défaut est app/views/layouts/application.html.erb.

  • <%= yield %> : C'est la ligne magique dans votre gabarit qui indique où le contenu spécifique de la vue sera inséré.
  • Structure typique :
    <!DOCTYPE html>
    <html>
    <head>
      <title>Mon App Rails</title>
      <%= csrf_meta_tags %>
      <%= csp_meta_tag %>
      <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
      <%= javascript_importmap_tags %>
    </head>
    <body>
      <header>
        <h1>Bienvenue sur mon blog !</h1>
        <nav>
          <%= link_to 'Accueil', root_path %> |
          <%= link_to 'Tous les articles', posts_path %>
        </nav>
      </header>
    
      <main>
        <%= yield %>
      </main>
    
      <footer>
        <p>&copy; 2023 Mon App Rails</p>
      </footer>
    </body>
    </html>
    
    Chaque vue rendue par un contrôleur est insérée à l'emplacement de <%= yield %> dans ce gabarit.

4. Les Partials (Partials) et les Helpers

Pour maintenir les vues propres, modulaires et DRY (Don't Repeat Yourself), Rails offre les partials et les helpers.

a. Les Partials

Un partial est un morceau de code de vue réutilisable. Son nom commence toujours par un underscore (ex: _user.html.erb).

  • Utilisation : Quand vous avez un bloc de code HTML qui se répète à plusieurs endroits, ou pour rendre le code d'une vue plus lisible en le décomposant.
  • Rendu d'un partial :
    • <%= render 'shared/menu' %> : Rend le partial _menu.html.erb dans le dossier app/views/shared.
    • <%= render 'post', post: @post %> : Rend le partial _post.html.erb en lui passant une variable locale post.
    • <%= render @posts %> : Une forme raccourcie pour rendre un partial pour chaque objet d'une collection. Si @posts est une collection d'objets Post, Rails cherchera le partial _post.html.erb et le rendra pour chaque Post, rendant chaque Post disponible sous le nom de variable locale post dans le partial.

b. Les Helpers

Les helpers sont des modules Ruby (situés dans app/helpers) qui contiennent des méthodes pouvant être appelées directement depuis les vues (et parfois les contrôleurs). Ils sont parfaits pour encapsuler la logique de présentation complexe ou pour générer du HTML.

  • Exemples courants intégrés à Rails :
    • link_to(text, path, options) : Génère un lien <a>.
    • image_tag(source, options) : Génère une balise <img>.
    • pluralize(count, singular_word, plural_word) : Affiche un mot au singulier ou au pluriel selon un nombre.
  • Créer vos propres helpers :
    # app/helpers/posts_helper.rb
    module PostsHelper
      def format_post_date(date)
        if date.today?
          "Aujourd'hui à #{date.strftime('%Hh%M')}"
        else
          date.strftime('%d/%m/%Y')
        end
      end
    end
    
    Vous pouvez ensuite l'utiliser dans votre vue : <%= format_post_date(@post.created_at) %>.

II. Les Formulaires : Saisir des Données Interactives

Les formulaires sont l'épine dorsale de l'interaction utilisateur dans une application web. Ils permettent aux utilisateurs de soumettre des informations (texte, fichiers, sélections) qui seront ensuite traitées par le serveur. Rails offre des helpers puissants pour simplifier la création et la gestion des formulaires.

1. Le rôle des Formulaires

  • Collecte d'entrée : Les formulaires HTML (<form>...</form>) sont le moyen standard de collecter des données auprès des utilisateurs.
  • Envoi de requêtes : Lorsque l'utilisateur soumet un formulaire, le navigateur envoie une requête HTTP (généralement POST ou PUT/PATCH) au serveur, contenant les données saisies.
  • Interaction avec le modèle : Ces données sont ensuite traitées par le contrôleur, qui les utilise pour créer, modifier ou supprimer des objets du modèle.

2. form_with : Le Helper de Formulaire Moderne

Historiquement, Rails a eu form_for et form_tag. Depuis Rails 5.1, form_with est le helper recommandé car il combine les avantages des deux précédents et est plus flexible. Il est idéal pour la création de formulaires RESTful (création/édition de ressources).

form_with génère automatiquement la balise <form>, configure la méthode HTTP et l'URL d'action en fonction de l'objet du modèle que vous lui passez. Il intègre également la protection CSRF (Cross-Site Request Forgery) automatiquement.

a. Créer un nouveau ressource (méthode POST)

Pour créer un nouveau ressource (ex: un nouvel article), vous devez initialiser une instance vide de ce ressource dans votre action de contrôleur, puis la passer à form_with.

Exemple de Contrôleur (app/controllers/posts_controller.rb) :

class PostsController < ApplicationController
  def new
    @post = Post.new # Crée une nouvelle instance vide de Post
  end

  def create
    @post = Post.new(post_params) # Tente de créer un Post avec les données du formulaire
    if @post.save
      redirect_to @post, notice: 'Article créé avec succès.'
    else
      render :new, status: :unprocessable_entity # Si la sauvegarde échoue, réaffiche le formulaire avec les erreurs
    end
  end

  private

  def post_params
    params.require(:post).permit(:title, :content) # Paramètres forts pour la sécurité
  end
end

Exemple de Vue pour la création (app/views/posts/new.html.erb) :

<h1>Créer un nouvel article</h1>

<%= form_with(model: @post, local: true) do |form| %>
  <% if form.object.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(form.object.errors.count, "erreur") %> a empêché cet article d'être sauvegardé :</h2>
      <ul>
        <% form.object.errors.full_messages.each do |message| %>
          <li><%= message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= form.label :title, "Titre" %>
    <%= form.text_field :title, class: "input-text" %>
  </div>

  <div class="field">
    <%= form.label :content, "Contenu" %>
    <%= form.text_area :content, class: "textarea-content" %>
  </div>

  <div class="actions">
    <%= form.submit "Créer l'article", class: "button-primary" %>
  </div>
<% end %>

<%= link_to 'Retour aux articles', posts_path %>

Explication du code :

  • <%= form_with(model: @post, local: true) do |form| %> :
    • model: @post : Indique à Rails que ce formulaire est lié à l'objet @post. Rails va automatiquement générer l'URL (/posts pour un nouveau post) et la méthode (POST).
    • local: true : S'assure que le formulaire est traité côté client (non-AJAX).
    • do |form| : Un bloc est passé au helper, et un objet form est retourné. Cet objet form est utilisé pour créer les champs du formulaire.
  • form.label :title : Génère une balise <label> pour le champ :title.
  • form.text_field :title : Génère une balise <input type="text"> pour l'attribut :title de l'objet @post. Si @post.title a déjà une valeur (par exemple, en cas d'erreur de validation et de réaffichage du formulaire), cette valeur sera pré-remplie.
  • form.text_area :content : Génère une balise <textarea> pour l'attribut :content.
  • form.submit "Créer l'article" : Génère un bouton <input type="submit"> avec le texte spécifié.
  • form.object.errors.any? et form.object.errors.full_messages : Ces lignes sont cruciales pour afficher les messages d'erreur de validation du modèle si la soumission du formulaire échoue (par exemple, si le titre est vide alors qu'il est requis).

b. Modifier un ressource existant (méthode PUT/PATCH)

Pour modifier un ressource existant, le processus est très similaire. La différence réside dans le fait que l'objet du modèle passé à form_with est déjà existant et contient des données.

Exemple de Contrôleur (app/controllers/posts_controller.rb) :

class PostsController < ApplicationController
  before_action :set_post, only: [:show, :edit, :update, :destroy]

  # ... new, create actions as above ...

  def edit
    # @post est déjà défini par before_action :set_post
  end

  def update
    if @post.update(post_params) # Tente de mettre à jour le Post
      redirect_to @post, notice: 'Article mis à jour avec succès.'
    else
      render :edit, status: :unprocessable_entity # Si la mise à jour échoue, réaffiche le formulaire
    end
  end

  private

  def set_post
    @post = Post.find(params[:id])
  end

  def post_params
    params.require(:post).permit(:title, :content)
  end
end

Exemple de Vue pour l'édition (app/views/posts/edit.html.erb) :

<h1>Modifier l'article : <%= @post.title %></h1>

<%= form_with(model: @post, local: true) do |form| %>
  <% if form.object.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(form.object.errors.count, "erreur") %> a empêché cet article d'être sauvegardé :</h2>
      <ul>
        <% form.object.errors.full_messages.each do |message| %>
          <li><%= message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= form.label :title, "Titre" %>
    <%= form.text_field :title, class: "input-text" %>
  </div>

  <div class="field">
    <%= form.label :content, "Contenu" %>
    <%= form.text_area :content, class: "textarea-content" %>
  </div>

  <div class="actions">
    <%= form.submit "Mettre à jour l'article", class: "button-primary" %>
  </div>
<% end %>

<%= link_to 'Afficher l\'article', @post %> |
<%= link_to 'Retour aux articles', posts_path %>

Rails est intelligent : puisque @post est un objet existant, form_with générera automatiquement une balise <form> avec la méthode patch (ou put) et l'URL posts/:id.

3. Les Paramètres Forts (Strong Parameters)

La méthode post_params que nous avons utilisée dans le contrôleur est un exemple de paramètres forts. C'est une fonctionnalité de sécurité essentielle de Rails.

  • params.require(:post) : Exige que le hachage params contienne une clé :post. Si elle est absente, Rails lève une erreur.
  • .permit(:title, :content) : Autorise uniquement les attributs :title et :content à être mass-assignés à l'objet Post. Cela empêche les utilisateurs malveillants d'injecter des données non autorisées dans votre base de données (ex: modifier un champ is_admin via un formulaire).

C'est une pratique obligatoire pour toute donnée provenant d'un formulaire et destinée à être sauvegardée ou mise à jour dans la base de données.

4. Autres Types de Champs de Formulaire

Le helper form offre une variété de méthodes pour différents types de champs HTML :

  • form.select(:category_id, Category.all.map { |c| [c.name, c.id] }) : Génère un menu déroulant (<select>).
  • form.check_box(:published) : Génère une case à cocher (<input type="checkbox">).
  • form.radio_button(:status, 'draft'), form.radio_button(:status, 'published') : Génère des boutons radio (<input type="radio">).
  • form.password_field(:password) : Génère un champ de mot de passe masqué (<input type="password">).
  • form.file_field(:image) : Génère un champ pour l'upload de fichiers (<input type="file">).
  • form.hidden_field(:user_id, value: current_user.id) : Génère un champ caché (<input type="hidden">).

Chacun de ces helpers prend le nom de l'attribut du modèle comme premier argument, et des options supplémentaires comme deuxième argument (par exemple, class, id, placeholder).

Conclusion

Les vues et les formulaires sont les piliers de l'interface utilisateur dans une application Ruby on Rails. En utilisant judicieusement les puissants helpers de Rails comme form_with, les gabarits, les partials et les helpers personnalisés, vous pouvez construire des interfaces utilisateur interactives, intuitives et surtout, sécurisées, avec une efficacité remarquable.

Vous avez appris :

  • Comment les vues (.html.erb) sont utilisées pour présenter les données et comment le code Ruby est intégré dans le HTML.
  • L'importance des gabarits (application.html.erb) pour une structure de page cohérente et DRY.
  • Comment les partials et les helpers améliorent la modularité et la lisibilité de votre code de vue.
  • La centralité de form_with pour la création de formulaires RESTful, gérant à la fois la création et la modification de ressources.
  • L'impératif des paramètres forts pour la sécurité de vos applications lors de la réception de données utilisateur.

La maîtrise de ces concepts vous ouvre les portes à la création d'expériences utilisateur riches et dynamiques, faisant de vous un développeur Rails plus complet et efficace. Pratiquez en créant vos propres modèles et en développant leurs interfaces complètes de création, lecture, mise à jour et suppression (CRUD) pour solidifier vos acquis.