Il y a quelque temps, je me suis lancé dans la lecture du code source de
Rails. Mon but étant de mieux comprendre son mécanisme et, peut-être, de
devenir un contributeur. J’ai choisi de commencer par ActiveRecord étant donné
que je trouve que c’est le module le plus “magique” de Rails. J’ai donc voulu
comprendre mieux cette magie apparente. Dans cet article, je vais tenter de
comprendre et d’expliquer ce qu’il se cache derrière ActiveRecord::Base
ainsi
que le noyau d’ActiveRecord.
Comme dans les articles précédents, je vais utiliser Pry pour explorer. Je vous conseille fortement de lire le code en même temps que l’article.
Pour commencer, je vais reprendre le code servant à créer des issues dans ActiveRecord en y plaçant un breakpoint afin de pouvoir étudier le comportement du modèle.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
ActiveRecord
Commençons par le commencement. Lorsque l’on charge la gem activerecord
, le fichier
activerecord.rb est inclus.
Comme on peut le voir en lisant le code, celui-ci commence par chargé ses
dépendances.
1 2 3 4 5 6 7 |
|
On comprend donc que ActiveRecord
dépend d’ActiveSupport
, ActiveModel
et
Arel
. ActiveSupport
est un module fournissant des fonctions utiles dans les
autres modules de Rails. ActiveModel
contient les informations spécifiques au
modèle du design pattern MVC
sans contenir les informations relatives à la
base de données. Arel
, quant à lui, permet de créer des requêtes SQL en Ruby.
Les premières lignes du module sont les suivantes :
1 2 3 |
|
Plutôt que de faire un require
, ActiveRecord
utilise le autoload
d’ActiveSupport
. ActiveSupport
permet de déterminer le nom du fichier à
charger en incluant le nom du module. Si l’on appelle autoload :Concern
depuis
le module ActiveSupport
, “active_support/concern” est déterminé. Cette chaîne
de caractère est ensuite envoyée à la fonction
autoload de
Ruby. De cette façon, les modules ne sont chargés qu’au moment où ils sont
appelés. C’est uniquement lorsque l’on utilisera ActiveSupport::Concern
dont
le fichier sera chargé. Il s’agit d’un procédé permettant d’économiser la
mémoire puisque l’on ne charge pas ce qui est inutile.
On continuant la lecture du code, on peut s’apercevoir que certain des modules
sont chargé dans un block eager_load
. Les chargements automatiques sont mis
dans un tableau. Les modules contenus dans ce tableau seront chargés quand la
fonction ActiveSupport.eager_load!
sera appelée.
Certains des éléments sont chargés dans block autoload_under
. Il s’agit,
simplement, d’un block ajoutant un dossier au chemin chargé.
Dans le bas du fichier, la fonction eager_load!
est définie. Celle-ci permet
de forcer le chargement de sous-modules. Cette fonction à été introduit dans
ce commit.
D’après ce que je comprends, ce code peut-être utile quand on fait du
multithreading ou pour être “CoW friendly”. J’avoue ne pas savoir ce que veut
dire “CoW”. Si quelqu’un peut m’éclairer, ça me plairait!
La dernière partie consiste en deux “hook”.
1 2 3 4 5 6 7 |
|
Ces appels vont activer des événements stockés dans des tableaux puis stock à nouveau pour une utilisation ultérieure.
ActiveRecord::Base
Tous les développeurs utilisant Ruby on Rails ont probablement fait un modèle
héritant de ActiveRecord::Base
. Quand on regarde le fichier
base.rb,
on s’aperçoit qu’il s’agit uniquement d’un fichier en incluant d’autres et
faisant des include
et des extend
d’autres modules. Deux lignes sont
intéressantes, ActiveSupport.run_load_hooks(:active_record, Base)
et include
Core
.
L’avant-dernière ligne exécute les événements stockés précédemment.
ActiveRecord
est donc indiqué comme étant le moteur par défaut de Arel
.
Conclusion
Voici donc le coeur d’ActiveRecord. Je vais tenter de poursuivre ma lecture du code et j’exposerai mes découvertes dans de prochains articles.