##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
Jean Romain Krupa

Merci pour cet article 🙏

8 months ago ·