ActiveRecord est probablement un des Gem qui impressionne le plus quand on
commence avec Rails. Comme par magie, ActiveRecord est capable de comprendre
seul quelle table est utilisée pour un modèle. Quand on connait Rails, on
comprend qu’il n’y a aucune magie. Dans cet article, je vais démystifier
ActiveRecord grâce à Pry.
Dans cet article, j’utilise la version 4.2 d’ActiveRecord.
Avant de commencer, il est important de comprendre comment explorer avec Pry. Je vous invite à lire sur le sujet car ce sont ces techniques que je vais utiliser ici.
Plusieurs éléments sont intéressants ici. Premièrement, les colonnes ne sont pas
encore connues par la classe étant donné que la variable @columns est nulle.
table_name est une méthode retournant la variable @table_name qui contient
déjà le nom de la table, “users” dans ce cas. connection.schema_cache semble contenir diverses
informations sur la base de données.
Avant d’exécuter connection.schema_cache.columns(table_name), schema_cache
ne contient pas les informations sur la structure de la table “users” tandis
qu’elles sont présentes par la suite.
Avec SQLite, cette requête renvoie les informations sur la table et c’est à
partir de ces informations qu’ActiveRecord reconstitut les données.
Cette requête fonctionne pour SQLite mais il en existe une similaire pour
Postgres.
123456789101112
#activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb:12defcolumn_definitions(table_name)# :nodoc:exec_query(<<-end_sql,'SCHEMA').rows SELECT a.attname, format_type(a.atttypid, a.atttypmod), pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod FROM pg_attribute a LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum end_sqlend
Il en est de même pour MySql.
123456789101112
#activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:464defcolumns(table_name)#:nodoc:sql="SHOW FULL FIELDS FROM #{quote_table_name(table_name)}"execute_and_free(sql,'SCHEMA')do|result|each_hash(result).mapdo|field|field_name=set_field_encoding(field[:Field])sql_type=field[:Type]cast_type=lookup_cast_type(sql_type)new_column(field_name,field[:Default],cast_type,sql_type,field[:Null]=="YES",field[:Collation],field[:Extra])endendend
Conclusion
Je pense que cette brève inspection nous suffit pour comprendre ce qu’il se
passe sous le capot. Le fonctionnement est assez simple et serait
facile à reproduire pour d’autres cas d’utilisation. Pry nous a permis, en
quelques minutes, de comprendre le code et de passer au travers l’apparente
magie de Rails.
Si vous voulez avoir d’autres explications sur le fonctionnement de Rails,
dites-le-moi et je ferais un processus similaire pour essayer de comprendre.