Développement Web

Rails : créer un CRUD complet avec scaffold et vues

12 min de lecture
📍 Article principal du parcours : Ruby on Rails : le guide complet pour débuter. Ce tutoriel fait partie du parcours « Ruby on Rails ». Pour la vue d’ensemble, commencez par le guide principal.

AtelierFix a une base de données, mais pour ajouter une réparation, Modou doit ouvrir une console et taper du Ruby — impensable au comptoir. Il lui faut de vrais écrans : la liste des réparations, un formulaire pour en saisir une, une page de détail, un bouton pour modifier, un autre pour supprimer. Ces cinq gestes portent un nom en développement : le CRUD (Create, Read, Update, Delete). Rails sait en générer l’ossature complète en une commande — c’est le célèbre scaffold. On va s’en servir, mais sans magie aveugle : vous comprendrez chaque fichier qu’il produit.

À la fin, n’importe qui dans l’atelier pourra créer, consulter, modifier et supprimer une réparation depuis le navigateur, avec un menu déroulant pour choisir le client — le tout adossé aux modèles bâtis au tutoriel précédent.

🎯 Ce que vous allez apprendre

  • Relier le CRUD aux sept actions REST d’un contrôleur Rails ;
  • Générer le contrôleur et les vues d’une ressource existante avec le scaffold ;
  • Câbler toutes les routes d’une ressource avec une seule ligne resources ;
  • Comprendre et écrire les strong parameters qui protègent vos formulaires ;
  • Transformer un champ brut en menu déroulant relié à une association.

🛠️ Ce que vous allez construire

L’interface de gestion des réparations d’AtelierFix : une page /reparations qui liste l’existant, un formulaire de création, des pages de détail et d’édition, et la suppression — tout cela fonctionnel et relié au bon client. C’est la première partie de l’application réellement utilisable par l’atelier.

Prérequis

CRUD et REST : la correspondance à retenir

Les quatre opérations du CRUD se traduisent, sur le web, en sept actions standard que Rails appelle les actions REST. Lire, c’est index (la liste) et show (un élément). Créer, c’est new (afficher le formulaire) puis create (enregistrer). Modifier, c’est edit (le formulaire pré-rempli) puis update (sauver). Supprimer, c’est destroy. Cette grammaire est universelle dans Rails : dès que vous gérez une « ressource » — réparations, clients, factures — vous retombez sur ces sept actions. Le scaffold n’invente rien : il écrit pour vous ces sept actions et les pages qui vont avec, en suivant les conventions vues jusqu’ici.

Étape 1 — Générer le contrôleur et les vues

Comme on a déjà créé le modèle Reparation à la main pour apprendre Active Record, on ne veut pas le recréer. Rails fournit exactement le bon outil : scaffold_controller génère le contrôleur et toutes les vues d’une ressource sans toucher au modèle ni à la base :

bin/rails generate scaffold_controller Reparation appareil:string panne:text statut:string prix:integer client:references

Cette commande crée app/controllers/reparations_controller.rb avec les sept actions REST, et le dossier app/views/reparations/ contenant les pages (liste, détail, formulaires) et deux partiels _reparation et _form. Aucune migration n’est lancée : votre table reparations existe déjà, on ne fait qu’ajouter l’interface web par-dessus. Prenez le temps d’ouvrir reparations_controller.rb : vous reconnaîtrez le découpage en actions vu au tutoriel MVC, en plus complet.

Étape 2 — Vérifier les routes

Bonne nouvelle : le générateur a déjà fait le travail. En plus du contrôleur et des vues, scaffold_controller a ajouté tout seul la ligne de routage dans config/routes.rb (sauf si vous passez l’option --skip-routes). Ouvrez le fichier pour le constater — vous y trouvez la déclaration de ressource, à côté de la route racine posée au tutoriel MVC :

Rails.application.routes.draw do
  root "dashboard#index"
  resources :reparations
end

Le mot-clé resources :reparations est l’un des plus rentables de Rails : il génère d’un coup les sept routes correspondant aux sept actions. Vérifiez-le :

bin/rails routes -g reparations

Vous voyez apparaître les routes GET /reparations (index), GET /reparations/new, POST /reparations (create), GET /reparations/:id (show), GET /reparations/:id/edit, PATCH /reparations/:id (update) et DELETE /reparations/:id (destroy). Une ligne, sept routes : c’est tout l’effet de levier de la convention REST.

Point d’étape — Lancez bin/rails server et ouvrez http://localhost:3000/reparations. La liste s’affiche (vide ou avec vos données de console), avec un lien « New reparation ». Si vous obtenez une erreur de route, vérifiez la présence de resources :reparations et que le serveur a bien redémarré.

Étape 3 — Visiter le CRUD généré

Avant de modifier quoi que ce soit, faites le tour du propriétaire dans le navigateur. Cliquez sur « New reparation » : un formulaire apparaît avec un champ par colonne. Remplissez-le, validez : vous arrivez sur la page de détail, avec un message « Reparation was successfully created ». De là, « Edit » rouvre le formulaire pré-rempli, et « Destroy » supprime après confirmation. En cinq minutes, vous avez un back-office fonctionnel — sans avoir écrit une ligne d’interface. C’est l’intérêt du scaffold : il vous donne une base qui marche, que vous adaptez ensuite à vos besoins réels.

Étape 4 — Comprendre les strong parameters

Ouvrez le bas de reparations_controller.rb : une méthode privée filtre les données du formulaire avant qu’elles touchent la base.

private

def reparation_params
  params.expect(reparation: [ :appareil, :panne, :statut, :prix, :client_id ])
end

Cette méthode est une barrière de sécurité indispensable. Sans elle, un utilisateur malveillant pourrait injecter des champs que vous n’attendez pas. params.expect — la forme moderne introduite avec Rails 8 — exige que le formulaire envoie bien un bloc reparation et n’autorise que les colonnes listées ; tout le reste est ignoré. Si vous ajoutez une colonne à la table un jour, pensez à l’ajouter ici, sinon le formulaire l’ignorera silencieusement. C’est le piège classique : « ma nouvelle case ne s’enregistre pas » vient presque toujours d’un champ oublié dans cette liste.

Étape 5 — Un menu déroulant pour le client

Le scaffold ne connaît pas l’intention derrière client:references : dans le formulaire, le client se saisit via un champ de texte brut où il faudrait taper l’identifiant à la main. C’est impraticable. On va le remplacer par un menu déroulant qui liste les clients par leur nom. Ouvrez app/views/reparations/_form.html.erb, repérez le champ relatif au client (un number_field sur client_id) et remplacez-le par :

<div>
  <%= form.label :client_id, "Client" %>
  <%= form.collection_select :client_id, Client.order(:nom), :id, :nom, { prompt: "Choisir un client" } %>
</div>

Décortiquons collection_select : le premier argument est l’attribut à remplir (client_id), le deuxième la liste à proposer (Client.order(:nom), tous les clients triés par nom), puis la valeur stockée pour chaque option (:id) et le texte affiché (:nom). Le prompt ajoute une ligne d’invite en tête. Désormais, l’utilisateur choisit « Awa Ndiaye » dans une liste, et Rails enregistre le bon client_id en coulisse. C’est ici que l’association bâtie au tutoriel précédent prend tout son sens dans l’interface.

Étape 6 — Vérification de bout en bout

Rechargez http://localhost:3000/reparations/new. Le formulaire affiche maintenant un menu déroulant de clients. Créez une réparation — appareil « Tecno Spark 10 », panne « Haut-parleur muet », statut « reçu », prix 12000, client « Awa Ndiaye » — et validez. Sur la page de détail, le client choisi apparaît bien rattaché. Revenez à la liste : votre réparation y figure. Le cycle complet création → lecture → modification → suppression fonctionne depuis le navigateur.

Point d’étape — AtelierFix est désormais une vraie application de gestion : on saisit une réparation sans toucher au code. Si le menu déroulant est vide, c’est que la table clients ne contient personne — créez un client en console ou scaffoldez aussi la ressource Client.

Dans les coulisses de l’action create

Le scaffold a écrit pour vous l’action qui enregistre le formulaire. La lire une fois éclaire tout le reste. Dans reparations_controller.rb, l’action ressemble à ceci :

def create
  @reparation = Reparation.new(reparation_params)
  if @reparation.save
    redirect_to @reparation, notice: "Réparation enregistrée."
  else
    render :new, status: :unprocessable_entity
  end
end

Tout se joue sur le if @reparation.save. Active Record tente d’enregistrer ; save renvoie true en cas de succès, false si une validation échoue. En cas de succès, on redirige vers la page de détail avec un message flash. En cas d’échec, on réaffiche le formulaire — pas une redirection, un rendu direct — pour conserver les données saisies et montrer les erreurs. C’est exactement là que les validations posées au tutoriel précédent paient : un statut hors de la liste autorisée fait échouer save, et le formulaire revient avec le message d’erreur, sans rien perdre de ce que l’utilisateur avait tapé.

Le status: :unprocessable_entity (code HTTP 422) n’est pas un détail : il indique au navigateur et à Turbo que la soumission a été refusée, ce qui permet à Hotwire de réafficher le formulaire correctement. Retenez ce duo redirect au succès, render à l’échec : c’est le squelette de presque toutes les actions create et update que vous écrirez en Rails.

🐞 Pièges fréquents

Symptôme / erreur Cause probable Correctif
Un nouveau champ ne s’enregistre pas Colonne absente des strong parameters L’ajouter dans params.expect(reparation: [ … ])
param is missing or the value is empty: reparation Formulaire qui n’envoie pas le bloc attendu Vérifier que le form_with model: @reparation est intact
Menu déroulant client vide Aucun client en base Créer au moins un Client (console ou scaffold)
Reparation must exist / client non enregistré client_id non listé dans les strong parameters L’ajouter à la liste autorisée

🌍 Adaptation au contexte ouest-africain

Le scaffold génère ses libellés et messages en anglais (« New reparation », « was successfully created »). Pour un atelier à Dakar ou Lomé, ces textes doivent passer en français — et idéalement rester traduisibles. Rails gère cela proprement via les fichiers de traduction dans config/locales/ : on y déclare ses libellés une fois, et les vues les réutilisent. Pour démarrer, le plus simple est d’éditer directement le texte des vues générées ; quand l’application grandit, basculez vers les fichiers de locales avec config.i18n.default_locale = :fr. Pensez-y tôt : reprendre une interface entièrement en anglais après coup coûte plus cher que de traduire au fur et à mesure.

✅ Récapitulatif

Vous avez transformé deux modèles silencieux en une application manipulable : la ressource Réparation dispose de ses sept actions REST, de ses pages, de ses formulaires, et d’un menu déroulant relié à l’association client. Vous avez surtout compris ce que le scaffold écrit — le contrôleur, les routes resources, les strong parameters — au lieu de le subir. C’est cette compréhension qui vous permettra demain de générer un CRUD puis de l’adapter sans crainte.

🧾 Aide-mémoire

Élément Rôle
generate scaffold_controller Nom … Contrôleur + vues pour un modèle existant
generate scaffold Nom … Modèle + migration + contrôleur + vues + route, d’un coup
resources :reparations Les 7 routes REST de la ressource
params.expect(reparation: [ … ]) Strong parameters (Rails 8)
form.collection_select … Menu déroulant relié à une association
bin/rails routes -g reparations Lister les routes d’une ressource

💪 À vous de jouer

Sur la page de détail d’une réparation, affichez le nom du client plutôt que son identifiant. Ouvrez app/views/reparations/show.html.erb (ou le partiel _reparation) et adaptez l’affichage.

Voir une solution
<p>
  <strong>Client :</strong>
  <%= @reparation.client.nom %>
</p>

Grâce au belongs_to :client, @reparation.client renvoie l’objet client, dont on lit le nom. L’association traverse l’interface jusqu’au bout.

Tutoriels frères

Pour aller plus loin

FAQ

Scaffold ou scaffold_controller ?
scaffold fait tout (modèle, migration, contrôleur, vues, route) : idéal pour démarrer une ressource de zéro. scaffold_controller ajoute le contrôleur, les vues et la route resources, mais ni le modèle ni la migration : c’est le bon choix quand le modèle existe déjà, comme ici.

Le scaffold est-il utilisable en production ?
Il fournit une base honnête, mais c’est un point de départ : on traduit les libellés, on soigne le design, on ajoute des contrôles d’accès. Considérez-le comme un brouillon fonctionnel, pas comme le produit fini.

Pourquoi params.expect et plus params.require().permit() ?
Les deux protègent vos formulaires. params.expect, introduit avec Rails 8, est plus concis et renvoie une erreur 400 propre (et non une 500) si quelqu’un trafique la structure des paramètres. C’est désormais la forme générée par défaut.

Dois-je scaffolder aussi les clients ?
Pour une vraie application, oui : Modou voudra gérer ses clients depuis le navigateur. La démarche est identique — bin/rails generate scaffold Client nom:string telephone:string si le modèle n’existait pas, ou scaffold_controller s’il existe déjà.

Partager