Ruby Framework

Ruby on Rails

Rails est le framework Ruby full-stack basé sur le principe de la convention plutôt que la configuration. Il gère les parties fastidieuses — noms de fichiers, noms de tables, routes — pour que vous puissiez vous concentrer sur votre produit.

intermediate15 min readUpdated 16 sept. 2026
app/controllers/posts_controller.rb
ruby
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  before_action :set_post, only: %i[show update destroy]

  def index
    @posts = Post.includes(:author).published.recent
  end

  def create
    @post = Current.user.posts.build(post_params)
    if @post.save
      redirect_to @post, notice: "Post created"
    else
      render :new, status: :unprocessable_entity
    end
  end

  private

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

  def post_params
    params.require(:post).permit(:title, :body)
  end
end
Sortie
2004
Créé par
David Heinemeier Hansson
Langage
Ruby
Style
Convention over configuration
Couche de données
Active Record ORM
Version
8.x

Pourquoi c'est important

Pourquoi Rails permet de développer si rapidement

Le CRUD en une après-midi

Les générateurs, les migrations et le scaffolding transforment un modèle de données en une application fonctionnelle connectée à une base de données en quelques heures plutôt qu'en plusieurs semaines.

Convention plutôt que configuration

Des valeurs par défaut cohérentes définissent les noms de fichiers, les noms de tables et les routes. Vous ne les surchargez que lorsque votre domaine nécessite réellement quelque chose de différent.

Des gems pour tout

L'authentification, les paiements, l'upload de fichiers, la recherche et les tableaux de bord d'administration disposent tous de gems matures et éprouvées, maintenues par la communauté.

Le tableau complet

MVC, conventions, gems

Rails donne à chaque requête la même structure : une route, un contrôleur, un modèle et une vue, nommés selon les attentes du framework.

Convention plutôt que configuration

Décider

Le framework fait le choix par défaut pour que vous n'ayez jamais à le faire. Un modèle Post correspond à une table posts et à une route /posts sans aucune configuration.

Active Record

Persister

Les modèles encapsulent les tables de la base de données avec des associations, des validations, des scopes et des migrations, gardant le SQL hors de votre code quotidien.

Ressources RESTful

Exposer

resources :posts déclare les sept routes CRUD conventionnelles, et les contrôleurs suivent les mêmes actions pour chaque ressource.

HTML5 en un coup d'oeil

La boîte à outils Rails

Routes RESTful

resources :posts vous donne index, show, new, create, edit, update et destroy.

Active Record

Les modèles, les associations et les migrations décrivent votre schéma en Ruby.

MVC

Les contrôleurs coordonnent, les modèles détiennent le domaine, les vues rendent la réponse.

Générateurs

rails generate écrit les modèles, contrôleurs, migrations et tests pour vous.

Hotwire

Turbo et Stimulus ajoutent de l'interactivité sans avoir besoin d'une SPA séparée.

Jobs d'arrière-plan

Active Job associé à Sidekiq exécute les tâches lentes en dehors du cycle de requête.

Un bref aperçu

Deux décennies de la méthode Rails

  1. 2004

    Rails est extrait de Basecamp

    David Heinemeier Hansson extrait un framework du code source de Basecamp et le publie en open source.

    04
  2. 2005

    Rails 1.0

    La première version stable fait de la convention plutôt que la configuration une idée dominante dans le développement web.

    05
  3. 2008

    Rails 2

    REST devient le style de routage par défaut et les ressources structurent chaque contrôleur.

    08
  4. 2010

    Rails 3 et Bundler

    Une API plus propre, Bundler pour les dépendances et la fusion avec Merb modernisent la stack.

    10
  5. 2016

    Rails 5 et Action Cable

    Les WebSockets arrivent dans le cœur du framework, et le mode API-only cible les front-ends de type page unique.

    16
  6. 2021

    Rails 7 et Hotwire

    Turbo et Stimulus remplacent Turbolinks, et les import maps permettent de livrer du JavaScript sans bundler.

    21
  7. 2024

    Rails 8

    Solid Queue, Solid Cache et Solid Cable s'exécutent sur la base de données, et Kamal simplifie le déploiement.

    24

Le guide complet

Ruby on Rails: Tout ce que vous devez savoir

Qu’est-ce que Ruby on Rails ?

Rails est un framework web full-stack pour Ruby. Il est livré avec tout ce dont une application web basée sur une base de données a besoin : un ORM, un routeur, une couche de vue, des tâches de fond (background jobs), des mailers, du caching, des WebSockets et un environnement de test. Au lieu de choisir et d’assembler ces composants vous-même, vous héritez d’une pile cohérente conçue pour fonctionner ensemble.

Son idée fondamentale est la convention plutôt que la configuration. Le framework suppose une structure logique — Post se trouve dans app/models/post.rb, correspond à une table posts et est servi par PostsController — et vous n’écrivez de la configuration que lorsque vous vous en écartez. L’équipe de Rails appelle cette philosophie omakase, le choix du chef : faites confiance aux valeurs par défaut, et vous irez plus vite.

C’est grâce à ce compromis que Rails propulse des produits allant de Basecamp et GitHub à Shopify et HEY depuis vingt ans, et pourquoi un seul développeur peut encore déployer une application sérieuse en un week-end.

La convention plutôt que la configuration

Chaque projet Rails possède la même structure, vous n’avez donc jamais à vous demander où placer un élément.

app/
├── controllers/    # request handling
├── models/         # domain and persistence
├── views/          # templates
├── jobs/           # background work
├── mailers/        # email
└── javascript/     # Stimulus controllers
config/
├── routes.rb       # the URL map
└── database.yml    # connection settings
db/
└── migrate/        # schema history

L’avantage est la prévisibilité. Un nouveau développeur ouvre le dépôt et sait déjà que le modèle User se trouve dans app/models/user.rb et que sa table est users. Le nommage n’est pas un débat de style ; c’est une interface sur laquelle le framework s’appuie.

Le cycle de requête MVC

Rails est un framework Model-View-Controller, et chaque requête HTTP suit le même chemin :

  1. Le Routing associe l’URL à une action du contrôleur.
  2. Le contrôleur charge ou modifie des données via les modèles.
  3. Les modèles appliquent les règles métier et communiquent avec la base de données.
  4. Une vue génère la réponse, généralement sous forme de HTML.
# config/routes.rb
Rails.application.routes.draw do
  resources :posts
  root "posts#index"
end

Une requête vers GET /posts arrive sur PostsController#index, qui prépare @posts, après quoi app/views/posts/index.html.erb est rendu. Le fait de garder chaque couche focalisée sur son rôle est ce qui permet à une application Rails de rester maintenable à mesure qu’elle grandit.

La ligne de commande est le framework

Vous touchez à peine à Rails via des fichiers de configuration. La majeure partie du travail s’effectue dans le terminal.

rails new shop --database=postgresql
cd shop

bin/rails generate scaffold Post title:string body:text published:boolean
bin/rails generate model Comment post:references body:text
bin/rails generate controller Pages home about

bin/rails db:create db:migrate
bin/rails server

generate écrit pour vous le modèle, la migration, le contrôleur, les routes, les vues et les tests, et la sortie du générateur vous indique les modifications effectuées. Lisez chaque fichier généré avant de le conserver — le moyen le plus rapide d’apprendre Rails est d’étudier ce qu’il écrit, puis de supprimer ce dont vous n’avez pas besoin.

Active Record : la couche modèle

Active Record est l’ORM. Une classe modèle encapsule une table de base de données, et une instance encapsule une ligne.

Migrations

Les migrations sont des modifications de schéma versionnées et réversibles stockées dans db/migrate. C’est la seule méthode supportée pour modifier la base de données.

class CreatePosts < ActiveRecord::Migration[8.0]
  def change
    create_table :posts do |t|
      t.string :title, null: false
      t.text :body, null: false
      t.boolean :published, default: false, null: false
      t.references :author, null: false, foreign_key: { to_table: :users }
      t.timestamps
    end

    add_index :posts, %i[published created_at]
  end
end

Exécutez bin/rails db:migrate pour l’appliquer et bin/rails db:rollback pour l’annuler. Comme change est réversible, Rails sait comment inverser les opérations sans que vous ayez à écrire de méthode down.

Associations

Les associations décrivent les relations et génèrent des méthodes pratiques.

class User < ApplicationRecord
  has_many :posts, dependent: :destroy
  has_many :comments, through: :posts
end

class Post < ApplicationRecord
  belongs_to :author, class_name: "User", inverse_of: :posts
  has_many :comments, dependent: :destroy
  has_one_attached :cover
end

Une fois cela en place, user.posts, post.author et post.comments.create(body: "...") fonctionnent tous, et dependent: :destroy empêche les lignes orphelines de rester dans la base de données.

Validations et scopes

Les validations protègent le domaine au niveau de la couche modèle, par laquelle passe chaque écriture.

class Post < ApplicationRecord
  validates :title, presence: true, length: { maximum: 120 }
  validates :body, presence: true
  validates :slug, uniqueness: true

  scope :published, -> { where(published: true) }
  scope :recent, -> { order(created_at: :desc) }

  before_validation :generate_slug, on: :create

  private

  def generate_slug
    self.slug ||= title.to_s.parameterize
  end
end

Les scopes retournent des relations, ils sont donc composables : Post.published.recent.limit(20) se lit comme une phrase et s’exécute comme une seule requête. Lorsqu’un scope dépasse une ligne ou deux, transformez-le en méthode de classe pour qu’il reste lisible.

Éviter les requêtes N+1

Le problème de performance le plus courant dans Rails est la requête N+1 : une requête pour une liste, puis une requête supplémentaire pour l’association de chaque ligne.

# Two queries total, no matter how many posts.
posts = Post.includes(:author, :comments).recent

posts.each do |post|
  puts "#{post.title} by #{post.author.name}"
end

Utilisez includes lorsque vous accéderez à l’association, preload lorsque vous souhaitez une requête séparée, et eager_load lorsque vous filtrez également sur l’association. Ajoutez la gem bullet à votre environnement de développement et elle signalera chaque N+1 avant qu’il n’atteigne la production.

Contrôleurs et routes RESTful

resources déclare les routes CRUD conventionnelles et les mappe aux actions du contrôleur portant des noms correspondants.

# config/routes.rb
Rails.application.routes.draw do
  resources :posts do
    resources :comments, only: %i[index create destroy]
  end

  namespace :api do
    namespace :v1 do
      resources :posts, only: %i[index show create update destroy]
    end
  end
end

Les contrôleurs restent légers. Ils chargent les données, appellent le domaine et choisissent une réponse. La logique métier appartient aux modèles ou aux objets de service, pas aux actions.

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

  def index
    @posts = Post.published.includes(:author).recent
  end

  def create
    @post = Post.new(post_params)
    if @post.save
      redirect_to @post, notice: "Post created."
    else
      render :new, status: :unprocessable_entity
    end
  end

  private

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

  def post_params
    params.require(:post).permit(:title, :body, :published, tag_ids: [])
  end
end

Les strong parameters ne sont pas optionnels. params.require(:post).permit(...) est la frontière qui empêche un client de modifier des colonnes que vous n’aviez pas prévu, telles que admin ou role.

Vues, ERB et layouts

Les vues sont des templates ERB : du HTML avec du Ruby intégré. Rails échappe les sorties par défaut, ce qui élimine toute une catégorie de bugs de cross-site scripting.

<%# app/views/posts/index.html.erb %>
<h1>Posts</h1>

<%= link_to "New post", new_post_path %>

<ul>
  <% @posts.each do |post| %>
    <li>
      <%= link_to post.title, post %>
      <span><%= pluralize(post.comments.size, "comment") %></span>
    </li>
  <% end %>
</ul>

Utilisez <%= %> pour afficher un résultat et <% %> pour exécuter du code sans affichage. Un layout dans app/views/layouts/application.html.erb enveloppe chaque page, et les partials — des fichiers commençant par un underscore — vous permettent de réutiliser du markup avec render "post", post: post ou simplement render @posts.

Hotwire : Turbo et Stimulus

Le Rails moderne ajoute de l’interactivité sans avoir besoin d’une application mono-page (SPA). Turbo intercepte les liens et les formulaires pour remplacer des fragments de page via le réseau ; Stimulus ajoute de petits comportements JavaScript là où vous en avez réellement besoin.

<%# Turbo Frames scope an update to one part of the page %>
<%= turbo_frame_tag "comments" do %>
  <%= render @post.comments %>
<% end %>
// app/javascript/controllers/dropdown_controller.js
import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
  static targets = ["menu"];

  toggle() {
    this.menuTarget.classList.toggle("hidden");
  }
}

C’est l’amélioration progressive (progressive enhancement) en pratique : le HTML rendu côté serveur est la base, et JavaScript vient l’enrichir. La plupart des applications Rails n’ont jamais besoin d’un routeur côté client.

Assets et import maps

Rails 7 a remplacé l’ancien pipeline Sprockets par les import maps par défaut et propose Propshaft comme pipeline d’assets plus simple. Vous pouvez ainsi “pinner” une bibliothèque sans passer par une étape de build Node.

bin/importmap pin local-time
bin/rails assets:precompile

Si vous préférez un bundler, bin/rails javascript:install:esbuild ou :vite permet de modifier la configuration. Le principe reste le même : servir ce que le navigateur comprend et garder la toolchain en retrait jusqu’à ce qu’elle devienne nécessaire.

Tâches de fond (Background jobs)

Tout ce qui est lent — l’envoi d’un e-mail, l’appel à une API, la génération d’un rapport — doit être placé dans un job, et non dans la requête. Active Job est l’interface commune ; l’adaptateur détermine où les jobs sont exécutés.

class PublishPostJob < ApplicationJob
  queue_as :default

  retry_on Net::ReadTimeout, wait: :polynomially_longer, attempts: 5

  def perform(post_id)
    Post.find(post_id).publish!
  end
end

PublishPostJob.perform_later(post.id)
# config/application.rb
config.active_job.queue_adapter = :solid_queue # or :sidekiq

Rails 8 est livré avec Solid Queue, qui stocke les jobs dans la base de données et ne nécessite pas Redis, ce qui réduit le nombre de composants mobiles pour une application sur un serveur unique. Sidekiq reste un excellent choix pour les volumes élevés.

Tests

Rails génère des tests pour chaque élément créé. Minitest est inclus par défaut et s’avère très rapide ; RSpec est l’alternative populaire, offrant une syntaxe plus expressive.

# test/models/post_test.rb
require "test_helper"

class PostTest < ActiveSupport::TestCase
  test "requires a title" do
    post = Post.new(body: "Hello")
    assert_not post.valid?
    assert_includes post.errors[:title], "can't be blank"
  end
end
# spec/models/post_spec.rb
RSpec.describe Post, type: :model do
  it "is invalid without a title" do
    expect(Post.new(body: "Hello")).not_to be_valid
  end
end

Les tests de contrôleur effectuent de réelles requêtes en cours de processus, ce qui permet de détecter des bugs de routage et de paramètres que les tests unitaires ne voient pas.

# test/controllers/posts_controller_test.rb
class PostsControllerTest < ActionDispatch::IntegrationTest
  test "lists published posts" do
    Post.create!(title: "Hi", body: "There", published: true)
    get posts_url
    assert_response :success
  end
end

Exécutez l’ensemble des tests avec bin/rails test ou bundle exec rspec. Ajoutez bin/rails test:system pour les tests système pilotés par navigateur lorsque le flux utilisateur est suffisamment critique pour nécessiter un test de bout en bout.

La console Rails

bin/rails console démarre votre application avec tous les modèles et helpers disponibles. C’est le moyen le plus rapide d’explorer vos données, de tester une requête ou de reproduire un bug.

bin/rails console
bin/rails console --sandbox   # rolls back all changes on exit
Post.published.recent.limit(5)
Post.where(published: false).update_all(published: true)
Post.includes(:author).find_each { |post| puts post.title }

--sandbox sert de filet de sécurité pendant vos expérimentations : toute écriture est annulée (rollback) lorsque vous quittez la console.

Bonnes pratiques

  • Gardez vos contrôleurs légers ; déplacez la logique métier dans les modèles ou des objets de service.
  • Utilisez le chargement anticipé (eager loading) des associations avec includes et surveillez les logs pour détecter les requêtes N+1.
  • Modifiez la base de données uniquement via des migrations, et commitez-les avec le code.
  • Utilisez des paramètres forts (strong parameters) pour chaque écriture et effectuez la validation au niveau de la couche modèle.
  • Ajoutez des index de base de données pour les colonnes sur lesquelles vous effectuez des filtres et des tris.
  • Déléguez les tâches lourdes à des jobs d’arrière-plan plutôt que de les traiter durant le cycle de requête.
  • Écrivez un test pour chaque bug corrigé, puis veillez à maintenir la rapidité de votre suite de tests.

Erreurs courantes

  • Rendre une liste sans includes et déployer un problème de requêtes N+1 en production.
  • Placer la logique métier dans les contrôleurs jusqu’à ce que les actions fassent des centaines de lignes.
  • Utiliser params[:post] directement au lieu des strong parameters.
  • Modifier db/schema.rb à la main au lieu d’écrire une migration.
  • Oublier les options dependent: et laisser des enregistrements orphelins.
  • Recourir à un service object ou à une gem avant que le modèle ne le justifie.
  • Exécuter des requêtes lourdes dans les vues au lieu de charger les données dans le contrôleur.

Et après ?

Rails enseigne une manière de penser durable : les ressources, les conventions et un emplacement unique pour chaque responsabilité. Si vous appréciez le modèle « batteries-included », Laravel applique la même philosophie en PHP, tandis que Django le fait en Python. Le routage de Rails étant basé sur les ressources, le guide sur les REST APIs explique les concepts sous-jacents. Et puisque la plupart des applications Rails s’appuient sur une base de données relationnelle, approfondissez ensuite vos connaissances en PostgreSQL.

En pratique

Les quatre fichiers derrière une ressource

Basculez entre la route, le contrôleur, le modèle et la migration pour voir comment Rails lie une ressource.

config/routes.rb
Rails.application.routes.draw do
  resources :posts do
    resources :comments, only: %i[index create destroy]
    member do
      post :publish
    end
  end

  namespace :api do
    namespace :v1 do
      resources :posts, only: %i[index show create update destroy]
    end
  end

  root "posts#index"
end

Chargement des associations

L'accès à une association à l'intérieur d'une boucle génère une requête par ligne. Le chargement anticipé (eager loading) permet à toute la page de s'exécuter avec seulement deux requêtes.

Préférer
posts = Post.includes(:author, :comments).recent
posts.each { |post| puts post.author.name }
Éviter
posts = Post.recent
posts.each { |post| puts post.author.name }
# one query per post: the classic N+1

Acceptation des entrées

Les paramètres forts (strong parameters) définissent une liste blanche de ce qu'une requête peut modifier. Passer le hash brut permet à un client de modifier n'importe quelle colonne, y compris les drapeaux admin.

Préférer
def post_params
  params.require(:post).permit(:title, :body, tag_ids: [])
end
Éviter
Post.new(params[:post])
# mass assignment: role and admin are fair game

Compromis

Rails est-il le choix par défaut idéal ?

Rails sacrifie une part de liberté pour gagner en vitesse de livraison. C'est un excellent compromis jusqu'à ce que votre application dépasse les conventions.

Strengths

  • Vous livrez des fonctionnalités, pas de la plomberie

    Le routage, les migrations, la validation, les mailers, les jobs et la mise en cache sont tous inclus et déjà connectés, permettant à une petite équipe de bâtir un produit conséquent.

  • Les conventions sont un langage commun

    Tout développeur Rails peut ouvrir n'importe quelle application Rails et savoir où se trouvent les éléments. Cela facilite énormément le recrutement et l'onboarding.

  • L'écosystème de gems est profond

    Devise, Pundit, Sidekiq, RSpec et d'innombrables autres résolvent les problèmes auxquels chaque application finit par être confrontée.

Trade-offs

  • La magie masque le framework

    La convention semble sans effort jusqu'à ce que quelque chose sorte du cadre. Le débogage nécessite de comprendre le code source de Rails, et pas seulement votre propre code.

  • La performance demande de l'attention

    Une application Rails naïve n'est pas lente, mais les requêtes N+1, l'absence d'index et les vues lourdes s'accumulent. Le profiling est une compétence requise, pas optionnelle.

  • La stack complète est directive

    Rails suppose l'utilisation de HTML, d'une base de données relationnelle et de sa propre gestion des assets. Si votre architecture diverge, vous lutterez contre les valeurs par défaut plus que vous ne les utiliserez.

FAQ

Foire aux questions

Keep learning

Related topics from the roadmap.

$ commencer à apprendre

Prêt à apprendre Rails ?

Notre tutoriel interactif vous guide à travers Rails pas à pas — avec des quiz et du vrai code que vous pouvez exécuter dans le navigateur.