##ORM #Ruby on Rails 🇫🇷

Comprendre et optimiser ActiveRecord dans Ruby on Rails

Sandri

Sandri

6 min read
👀 Comprendre ActiveRecord dans Ruby on Rails :

Ruby on Rails (RoR), rappelons-le, est un framework web monolithique, qui s'appuie sur le modèle MVC (Model View Controller). Sa philosophie "convention over configuration" guide efficacement le développement.
L'un des composants qui rend RoR particulièrement puissant est ActiveRecord, facilitant grandement l'interaction avec la base de données.


🔎 Qu'est-ce qu'ActiveRecord ?

ActiveRecord est un ORM (Object Relational Mapping). En d'autres termes, il constitue le lien entre les modèles de notre application (qui sont des objets) et notre base de données relationnelle. Il nous permet de manipuler des bases de données comme si nous manipulions des objets Ruby classiques.
Chaque table de notre base de données correspond à une classe Ruby, et chaque ligne de cette table à une instance de cette classe.

Prenons un exemple :
Si vous avez une table "users" dans votre base de données, vous aurez une classe User dans votre application. Chaque utilisateur sera une instance de la classe User, et chaque attribut de l'utilisateur (nom, email, etc.) correspondra à un champ de la table "users".
C'est ainsi qu'ActiveRecord vous permet de manipuler vos données de manière intuitive, rendant votre code plus lisible et facile à maintenir.

Il cache également la complexité des requêtes SQL, rendant ainsi votre code plus lisible et facile à maintenir.
Dans les sections suivantes, nous allons explorer certaines de ces fonctionnalités plus en détail.


💼 ActiveRecord et les opérations CRUD

ActiveRecord simplifie grandement la gestion des opérations CRUD (Create, Read, Update, Delete) sur les bases de données.
Il vous permet d'effectuer ces opérations en utilisant du code Ruby standard, sans avoir à écrire manuellement des requêtes SQL.

Par exemple, pour créer (Create) un nouvel enregistrement, vous pouvez utiliser la méthode new ou create :

    # Avec new
    student = Student.new
    student.name = "Alice"
    student.save

    # Avec create
    student = Student.create(name: "Alice")

Chaque fois que vous utilisez ActiveRecord pour effectuer une opération CRUD, plusieurs choses se passent. 
  • D'abord, ActiveRecord convertit ces opérations en requêtes SQL appropriées. 
  • Ensuite, il exécute ces requêtes sur votre base de données. 
  • Enfin, il convertit les résultats SQL obtenus en objets Ruby que vous pouvez utiliser dans votre application.

Par exemple, si vous utilisez ActiveRecord pour rechercher un étudiant avec un certain nom :

    student = Student.find_by(name: "Alice")

ActiveRecord traduit cette ligne en une requête SQL qui pourrait ressembler à ceci :

    SELECT * FROM students WHERE name = 'Alice' LIMIT 1;

De même, si vous utilisez ActiveRecord pour créer un nouvel enregistrement :

    student = Student.create(name: "Bob", age: 20)

ActiveRecord pourrait traduire cette instruction en quelque chose comme :

    INSERT INTO students (name, age) VALUES ('Bob', 20);

L'un des grands avantages de ceci est que vous n'avez généralement pas besoin d'écrire de SQL vous-même lorsque vous utilisez ActiveRecord.
Vous pouvez effectuer une grande variété d'opérations de base de données en utilisant uniquement le code Ruby.
Cela rend votre code plus lisible et plus facile à maintenir. De plus, puisque ActiveRecord "comprend" votre schéma de base de données, il peut optimiser les requêtes pour vous, ce qui peut améliorer les performances de votre application.


🔗 Gestion des associations entre modèles

Une autre caractéristique clé d'ActiveRecord est la possibilité de gérer les associations entre les modèles, ce qui simplifie grandement la gestion des données liées.
Par exemple, si vous avez une table "users" et une table "articles" dans votre base de données, vous pouvez définir une association entre les deux en déclarant que chaque utilisateur à plusieurs articles. Cela vous permet de récupérer facilement tous les articles d'un utilisateur donné, ou de récupérer l'utilisateur qui a écrit un article donné.


⚠️ Le problème N+1 et sa résolution

Bien que les ORM offrent de nombreux avantages, ils ont aussi des inconvénients.
Par exemple, ils peuvent parfois conduire à une performance moins performante si on ne fait pas attention, notamment à cause du problème du N+1.

Le problème N+1 est un problème courant lié aux performances dans les applications qui utilisent un ORM comme ActiveRecord.
Il se produit lorsque nous faisons un grand nombre de requêtes similaires à notre base de données, ce qui peut ralentir considérablement notre application.

Par exemple, si vous avez un modèle User qui a plusieurs Posts (ici, les "posts" sont considérés comme les "enfants" du modèle User), et que vous voulez afficher tous les utilisateurs avec tous leurs posts, vous pourriez être tenté de faire quelque chose comme ça :

    users = User.all

    users.each do |user|
      puts "User: #{user.name}"
      user.posts.each do |post|
        puts "Post: #{post.title}"
      end
    end

Ce code semble assez innocent, mais il est en fait très inefficace. Ce qui se passe ici, c'est que pour chaque utilisateur, une nouvelle requête est faite pour aller chercher tous ses posts. Donc, si vous avez N utilisateurs, vous effectuez 1 requête pour obtenir tous les utilisateurs, puis N requêtes supplémentaires pour obtenir les posts de chaque utilisateur - d'où le nom "problème N+1".

La bonne nouvelle est qu'ActiveRecord fournit une solution simple à ce problème :
L'utilisation de includes pour précharger tous les posts (les "enfants") en une seule requête.
Voici à quoi ressemblerait le code corrigé :

    users = User.includes(:posts)

    users.each do |user|
      puts "User: #{user.name}"
      user.posts.each do |post|
        puts "Post: #{post.title}"
      end
    end

Comme vous pouvez le voir, nous avons simplement ajouté un .includes(:posts) à notre requête initiale.
Ici ActiveRecord effectue seulement 2 requêtes : une pour obtenir tous les utilisateurs, et une autre pour obtenir tous les posts.
Peu importe le nombre d'utilisateurs que nous avons, nous n'effectuons jamais plus de 2 requêtes. C'est ce qu'on appelle le préchargement (eager loading).

Il existe plusieurs autres astuces et méthodes pour optimiser vos requêtes avec ActiveRecord.
Par exemple, vous pouvez utiliser la gem Bullet pour identifier les requêtes N+1 dans votre application.
Vous pouvez également utiliser des associations complexes avec includes pour précharger des données à partir de plusieurs modèles à la fois.

Le problème N+1 est un problème commun dans beaucoup de projets.
En connaissant ce problème et en utilisant des techniques de préchargement, vous pouvez améliorer considérablement les performances de votre application.

🏁 Conclusion :

ActiveRecord facilite grandement l'interaction avec votre base de données, vous permettant de vous concentrer sur votre logique métier plutôt que sur les détails techniques de la gestion d'une base de données.
Avec son approche orientée objet et sa facilité d'utilisation, il est facile de comprendre pourquoi ActiveRecord est une partie si essentielle de Ruby on Rails et de son paradigme "convention over configuration".
Feed
Sign up or Sign in to comment
Jeanro Krupa

Merci pour cet article 🙏

10 months ago ·