1 Qu'est-ce qu'un moteur ?
Les moteurs peuvent être considérés comme des applications miniatures qui fournissent des fonctionnalités à leurs applications hôtes. Une application Rails est en réalité juste un moteur "surpuissant", avec la classe Rails::Application
héritant une grande partie de son comportement de Rails::Engine
.
Par conséquent, les moteurs et les applications peuvent être considérés comme presque la même chose, avec des différences subtiles, comme vous le verrez tout au long de ce guide. Les moteurs et les applications partagent également une structure commune.
Les moteurs sont également étroitement liés aux plugins. Les deux partagent une structure de répertoire lib
commune et sont tous deux générés à l'aide du générateur rails plugin new
. La différence est qu'un moteur est considéré comme un "plugin complet" par Rails (comme indiqué par l'option --full
passée à la commande du générateur). Nous utiliserons en fait l'option --mountable
ici, qui inclut toutes les fonctionnalités de --full
, et même plus. Ce guide se référera à ces "plugins complets" simplement comme des "moteurs". Un moteur peut être un plugin, et un plugin peut être un moteur.
Le moteur qui sera créé dans ce guide s'appellera "blorgh". Ce moteur fournira des fonctionnalités de blog à ses applications hôtes, permettant la création de nouveaux articles et commentaires. Au début de ce guide, vous travaillerez uniquement dans le moteur lui-même, mais dans les sections suivantes, vous verrez comment l'intégrer dans une application.
Les moteurs peuvent également être isolés de leurs applications hôtes. Cela signifie qu'une application peut avoir un chemin fourni par un helper de routage tel que articles_path
et utiliser un moteur qui fournit également un chemin appelé articles_path
, et les deux ne se chevaucheraient pas. En plus de cela, les contrôleurs, les modèles et les noms de table sont également mis en namespace. Vous verrez comment faire cela plus tard dans ce guide.
Il est important de garder à l'esprit en tout temps que l'application devrait toujours avoir la priorité sur ses moteurs. Une application est l'objet qui a le dernier mot sur ce qui se passe dans son environnement. Le moteur ne devrait que l'améliorer, plutôt que de le changer radicalement.
Pour voir des démonstrations d'autres moteurs, consultez Devise, un moteur qui fournit une authentification pour ses applications parent, ou Thredded, un moteur qui fournit des fonctionnalités de forum. Il y a aussi Spree qui fournit une plateforme de commerce électronique, et Refinery CMS, un moteur de CMS.
Enfin, les moteurs n'auraient pas été possibles sans le travail de James Adam, Piotr Sarnacki, l'équipe principale de Rails et un certain nombre d'autres personnes. Si vous les rencontrez un jour, n'oubliez pas de les remercier !
2 Générer un moteur
Pour générer un moteur, vous devrez exécuter le générateur de plugin et lui passer les options appropriées selon les besoins. Pour l'exemple "blorgh", vous devrez créer un moteur "mountable", en exécutant cette commande dans un terminal :
$ rails plugin new blorgh --mountable
La liste complète des options pour le générateur de plugin peut être consultée en tapant :
$ rails plugin --help
L'option --mountable
indique au générateur que vous souhaitez créer un moteur "mountable" et isolé par namespace. Ce générateur fournira la même structure squelette que l'option --full
. L'option --full
indique au générateur que vous souhaitez créer un moteur, y compris une structure squelette qui fournit ce qui suit :
- Une arborescence de répertoires
app
Un fichier
config/routes.rb
:Rails.application.routes.draw do end
Un fichier à
lib/blorgh/engine.rb
, qui est identique en fonction à un fichierconfig/application.rb
standard d'une application Rails :module Blorgh class Engine < ::Rails::Engine end end
L'option --mountable
ajoutera à l'option --full
:
- Des fichiers de manifeste des assets (
blorgh_manifest.js
etapplication.css
) - Un modèle de stub
ApplicationController
mis en namespace - Un modèle de stub
ApplicationHelper
mis en namespace - Un modèle de vue de mise en page pour le moteur
L'isolation par namespace dans
config/routes.rb
:ruby Blorgh::Engine.routes.draw do end
- Isolation de l'espace de noms dans
lib/blorgh/engine.rb
:
- Isolation de l'espace de noms dans
module Blorgh
class Engine < ::Rails::Engine
isolate_namespace Blorgh
end
end
De plus, l'option --mountable
indique au générateur de monter le moteur à l'intérieur de l'application de test fictive située dans test/dummy
en ajoutant le code suivant au fichier de routes de l'application fictive situé dans test/dummy/config/routes.rb
:
mount Blorgh::Engine => "/blorgh"
2.1 À l'intérieur d'un moteur
2.1.1 Fichiers critiques
À la racine du répertoire de ce tout nouveau moteur se trouve un fichier blorgh.gemspec
. Lorsque vous incluez le moteur dans une application ultérieurement, vous le ferez avec cette ligne dans le fichier Gemfile
de l'application Rails :
gem 'blorgh', path: 'engines/blorgh'
N'oubliez pas d'exécuter bundle install
comme d'habitude. En le spécifiant comme une gemme dans le Gemfile
, Bundler le chargera en tant que tel, en analysant ce fichier blorgh.gemspec
et en exigeant un fichier dans le répertoire lib
appelé lib/blorgh.rb
. Ce fichier exige le fichier blorgh/engine.rb
(situé dans lib/blorgh/engine.rb
) et définit un module de base appelé Blorgh
.
require "blorgh/engine"
module Blorgh
end
CONSEIL : Certains moteurs choisissent d'utiliser ce fichier pour mettre des options de configuration globales pour leur moteur. C'est une assez bonne idée, donc si vous voulez offrir des options de configuration, le fichier où le module
de votre moteur est défini est parfait pour cela. Placez les méthodes à l'intérieur du module et vous serez prêt à partir.
À l'intérieur de lib/blorgh/engine.rb
se trouve la classe de base du moteur :
module Blorgh
class Engine < ::Rails::Engine
isolate_namespace Blorgh
end
end
En héritant de la classe Rails::Engine
, cette gemme notifie à Rails qu'il y a un moteur au chemin spécifié et montera correctement le moteur à l'intérieur de l'application, effectuant des tâches telles que l'ajout du répertoire app
du moteur au chemin de chargement des modèles, des mailers, des contrôleurs et des vues.
La méthode isolate_namespace
mérite une attention particulière. Cet appel est responsable de l'isolation des contrôleurs, des modèles, des routes et d'autres éléments dans leur propre espace de noms, à l'écart des composants similaires à l'intérieur de l'application. Sans cela, il est possible que les composants du moteur puissent "fuiter" dans l'application, provoquant des perturbations indésirables, ou que des composants importants du moteur puissent être remplacés par des éléments de même nom à l'intérieur de l'application. L'un des exemples de ces conflits est les helpers. Sans appeler isolate_namespace
, les helpers du moteur seraient inclus dans les contrôleurs d'une application.
REMARQUE : Il est vivement recommandé de laisser la ligne isolate_namespace
à l'intérieur de la définition de la classe Engine
. Sans cela, les classes générées dans un moteur peuvent entrer en conflit avec une application.
Ce que signifie cette isolation de l'espace de noms, c'est qu'un modèle généré par un appel à bin/rails generate model
, tel que bin/rails generate model article
, ne sera pas appelé Article
, mais sera plutôt mis dans un espace de noms et appelé Blorgh::Article
. De plus, la table pour le modèle est mise dans un espace de noms, devenant blorgh_articles
, plutôt que simplement articles
. De même pour l'espace de noms des contrôleurs, un contrôleur appelé ArticlesController
devient Blorgh::ArticlesController
et les vues pour ce contrôleur ne se trouvent pas dans app/views/articles
, mais plutôt dans app/views/blorgh/articles
. Les mailers, les jobs et les helpers sont également mis dans un espace de noms.
Enfin, les routes seront également isolées à l'intérieur du moteur. C'est l'une des parties les plus importantes de l'isolation des espaces de noms, et elle est discutée plus en détail dans la section Routes de ce guide.
2.1.2 Répertoire app
À l'intérieur du répertoire app
, on trouve les répertoires standard assets
, controllers
, helpers
, jobs
, mailers
, models
et views
que vous devriez connaître d'une application. Nous examinerons plus en détail les modèles dans une section ultérieure, lorsque nous écrirons le moteur.
Dans le répertoire app/assets
, on trouve les répertoires images
et stylesheets
qui, là encore, devraient vous être familiers en raison de leur similitude avec une application. Une différence ici, cependant, est que chaque répertoire contient un sous-répertoire avec le nom du moteur. Étant donné que ce moteur va être mis en espace de noms, ses assets devraient l'être aussi.
Dans le répertoire app/controllers
, il y a un répertoire blorgh
qui contient un fichier appelé application_controller.rb
. Ce fichier fournira toute fonctionnalité commune pour les contrôleurs du moteur. Le répertoire blorgh
est l'endroit où les autres contrôleurs du moteur iront. En les plaçant dans ce répertoire mis en espace de noms, vous évitez qu'ils entrent en conflit avec des contrôleurs portant le même nom dans d'autres moteurs ou même dans l'application.
REMARQUE : La classe ApplicationController
à l'intérieur d'un moteur est nommée exactement comme une application Rails afin de faciliter la conversion de vos applications en moteurs.
NOTE : Si l'application parente s'exécute en mode "classic", vous pouvez rencontrer une situation où votre contrôleur de moteur hérite du contrôleur de l'application principale et non du contrôleur de l'application de votre moteur. La meilleure façon d'éviter cela est de passer en mode "zeitwerk" dans l'application parente. Sinon, utilisez "require_dependency" pour vous assurer que le contrôleur de l'application du moteur est chargé. Par exemple :
# NÉCESSAIRE UNIQUEMENT EN MODE "classic".
require_dependency "blorgh/application_controller"
module Blorgh
class ArticlesController < ApplicationController
# ...
end
end
AVERTISSEMENT : N'utilisez pas "require" car cela rompra le rechargement automatique des classes dans l'environnement de développement - en utilisant "require_dependency", vous vous assurez que les classes sont chargées et déchargées correctement.
Tout comme pour "app/controllers", vous trouverez un sous-répertoire "blorgh" dans les répertoires "app/helpers", "app/jobs", "app/mailers" et "app/models" contenant le fichier "application_*.rb" associé pour regrouper les fonctionnalités communes. En plaçant vos fichiers dans ce sous-répertoire et en utilisant des espaces de noms pour vos objets, vous évitez qu'ils entrent en conflit avec des éléments portant le même nom dans d'autres moteurs ou même dans l'application.
Enfin, le répertoire "app/views" contient un dossier "layouts", qui contient un fichier "blorgh/application.html.erb". Ce fichier vous permet de spécifier une mise en page pour le moteur. Si ce moteur doit être utilisé comme un moteur autonome, vous ajouterez toute personnalisation à sa mise en page dans ce fichier, plutôt que dans le fichier "app/views/layouts/application.html.erb" de l'application.
Si vous ne souhaitez pas imposer une mise en page aux utilisateurs du moteur, vous pouvez supprimer ce fichier et référencer une mise en page différente dans les contrôleurs de votre moteur.
2.1.3 Répertoire "bin"
Ce répertoire contient un fichier, "bin/rails", qui vous permet d'utiliser les sous-commandes et les générateurs de Rails comme vous le feriez dans une application. Cela signifie que vous pourrez générer très facilement de nouveaux contrôleurs et modèles pour ce moteur en exécutant des commandes comme celle-ci :
$ bin/rails generate model
Gardez à l'esprit, bien sûr, que tout ce qui est généré avec ces commandes à l'intérieur d'un moteur qui a "isolate_namespace" dans la classe "Engine" sera mis en espace de noms.
2.1.4 Répertoire "test"
Le répertoire "test" est l'endroit où se trouvent les tests pour le moteur. Pour tester le moteur, il y a une version simplifiée d'une application Rails intégrée à l'intérieur, dans "test/dummy". Cette application montera le moteur dans le fichier "test/dummy/config/routes.rb" :
Rails.application.routes.draw do
mount Blorgh::Engine => "/blorgh"
end
Cette ligne monte le moteur sur le chemin "/blorgh", ce qui le rend accessible uniquement à cet endroit dans l'application.
À l'intérieur du répertoire de test, il y a le répertoire "test/integration", où les tests d'intégration pour le moteur doivent être placés. D'autres répertoires peuvent également être créés dans le répertoire "test". Par exemple, vous pouvez créer un répertoire "test/models" pour vos tests de modèle.
3 Fournir des fonctionnalités de moteur
Le moteur couvert par ce guide fournit des fonctionnalités de soumission d'articles et de commentaires, et suit un fil similaire au Guide de démarrage, avec quelques nouveautés.
NOTE : Pour cette section, assurez-vous d'exécuter les commandes à la racine du répertoire du moteur "blorgh".
3.1 Générer une ressource d'article
La première chose à générer pour un moteur de blog est le modèle "Article" et le contrôleur associé. Pour générer rapidement cela, vous pouvez utiliser le générateur de squelette Rails.
$ bin/rails generate scaffold article title:string text:text
Cette commande affichera ces informations :
invoke active_record
create db/migrate/[timestamp]_create_blorgh_articles.rb
create app/models/blorgh/article.rb
invoke test_unit
create test/models/blorgh/article_test.rb
create test/fixtures/blorgh/articles.yml
invoke resource_route
route resources :articles
invoke scaffold_controller
create app/controllers/blorgh/articles_controller.rb
invoke erb
create app/views/blorgh/articles
create app/views/blorgh/articles/index.html.erb
create app/views/blorgh/articles/edit.html.erb
create app/views/blorgh/articles/show.html.erb
create app/views/blorgh/articles/new.html.erb
create app/views/blorgh/articles/_form.html.erb
invoke test_unit
create test/controllers/blorgh/articles_controller_test.rb
create test/system/blorgh/articles_test.rb
invoke helper
create app/helpers/blorgh/articles_helper.rb
invoke test_unit
La première chose que fait le générateur de squelette est d'appeler le générateur "active_record", qui génère une migration et un modèle pour la ressource. Notez ici, cependant, que la migration s'appelle "create_blorgh_articles" au lieu de "create_articles" habituel. Cela est dû à l'appel de la méthode "isolate_namespace" dans la définition de la classe "Blorgh::Engine". Le modèle ici est également mis en espace de noms, étant placé dans "app/models/blorgh/article.rb" au lieu de "app/models/article.rb" en raison de l'appel à "isolate_namespace" dans la classe "Engine".
Ensuite, le générateur "test_unit" est appelé pour ce modèle, générant un test de modèle à "test/models/blorgh/article_test.rb" (au lieu de "test/models/article_test.rb") et une fixture à "test/fixtures/blorgh/articles.yml" (au lieu de "test/fixtures/articles.yml").
Ensuite, une ligne pour la ressource est insérée dans le fichier "config/routes.rb" du moteur. Cette ligne est simplement "resources :articles", transformant le fichier "config/routes.rb" du moteur en ceci :
ruby
Blorgh::Engine.routes.draw do
resources :articles
end
Notez ici que les routes sont dessinées sur l'objet Blorgh::Engine
plutôt que sur la classe YourApp::Application
. Cela permet de confiner les routes du moteur au moteur lui-même et de les monter à un point spécifique comme indiqué dans la section répertoire de test. Cela permet également d'isoler les routes du moteur de celles qui se trouvent dans l'application. La section Routes de ce guide en décrit les détails.
Ensuite, le générateur scaffold_controller
est invoqué, générant un contrôleur appelé Blorgh::ArticlesController
(à app/controllers/blorgh/articles_controller.rb
) et ses vues associées à app/views/blorgh/articles
. Ce générateur génère également des tests pour le contrôleur (test/controllers/blorgh/articles_controller_test.rb
et test/system/blorgh/articles_test.rb
) et un helper (app/helpers/blorgh/articles_helper.rb
).
Tout ce que ce générateur a créé est soigneusement mis en namespace. La classe du contrôleur est définie dans le module Blorgh
:
module Blorgh
class ArticlesController < ApplicationController
# ...
end
end
NOTE : La classe ArticlesController
hérite de Blorgh::ApplicationController
, et non de ApplicationController
de l'application.
Le helper dans app/helpers/blorgh/articles_helper.rb
est également mis en namespace :
module Blorgh
module ArticlesHelper
# ...
end
end
Cela permet d'éviter les conflits avec tout autre moteur ou application qui pourrait également avoir une ressource d'article.
Vous pouvez voir ce que le moteur a jusqu'à présent en exécutant bin/rails db:migrate
à la racine de notre moteur pour exécuter la migration générée par le générateur de scaffold, puis en exécutant bin/rails server
dans test/dummy
. Lorsque vous ouvrez http://localhost:3000/blorgh/articles
, vous verrez le scaffold par défaut qui a été généré. Cliquez autour ! Vous venez de générer les premières fonctions de votre premier moteur.
Si vous préférez jouer dans la console, bin/rails console
fonctionnera également comme une application Rails. N'oubliez pas : le modèle Article
est mis en namespace, donc pour le référencer, vous devez l'appeler Blorgh::Article
.
irb> Blorgh::Article.find(1)
=> #<Blorgh::Article id: 1 ...>
Une dernière chose est que la ressource articles
de ce moteur devrait être la racine du moteur. Chaque fois que quelqu'un accède au chemin racine où le moteur est monté, il devrait voir une liste d'articles. Cela peut être réalisé en insérant cette ligne dans le fichier config/routes.rb
à l'intérieur du moteur :
root to: "articles#index"
Maintenant, les gens n'auront besoin d'aller qu'à la racine du moteur pour voir tous les articles, plutôt que de visiter /articles
. Cela signifie qu'au lieu de http://localhost:3000/blorgh/articles
, vous n'avez maintenant qu'à aller à http://localhost:3000/blorgh
.
3.2 Génération d'une ressource de commentaires
Maintenant que le moteur peut créer de nouveaux articles, il est logique d'ajouter également une fonctionnalité de commentaires. Pour cela, vous devrez générer un modèle de commentaire, un contrôleur de commentaire, puis modifier le scaffold des articles pour afficher les commentaires et permettre aux utilisateurs d'en créer de nouveaux.
Depuis la racine du moteur, exécutez le générateur de modèle. Indiquez-lui de générer un modèle Comment
, avec la table associée ayant deux colonnes : un entier article_id
et une colonne de texte text
.
$ bin/rails generate model Comment article_id:integer text:text
Cela produira la sortie suivante :
invoke active_record
create db/migrate/[timestamp]_create_blorgh_comments.rb
create app/models/blorgh/comment.rb
invoke test_unit
create test/models/blorgh/comment_test.rb
create test/fixtures/blorgh/comments.yml
Cet appel au générateur générera uniquement les fichiers de modèle nécessaires, en les mettant en namespace sous un répertoire blorgh
et en créant une classe de modèle appelée Blorgh::Comment
. Exécutez maintenant la migration pour créer notre table blorgh_comments
:
$ bin/rails db:migrate
Pour afficher les commentaires sur un article, modifiez app/views/blorgh/articles/show.html.erb
et ajoutez cette ligne avant le lien "Edit" :
<h3>Comments</h3>
<%= render @article.comments %>
Cette ligne nécessitera qu'une association has_many
pour les commentaires soit définie sur le modèle Blorgh::Article
, ce qui n'est pas le cas pour le moment. Pour en définir une, ouvrez app/models/blorgh/article.rb
et ajoutez cette ligne dans le modèle :
has_many :comments
Le modèle devient alors :
module Blorgh
class Article < ApplicationRecord
has_many :comments
end
end
NOTE : Comme has_many
est défini à l'intérieur d'une classe qui se trouve dans le module Blorgh
, Rails saura que vous voulez utiliser le modèle Blorgh::Comment
pour ces objets, il n'est donc pas nécessaire de le spécifier en utilisant l'option :class_name
ici.
Ensuite, il faut un formulaire pour que les commentaires puissent être créés sur un article. Pour ajouter cela, placez cette ligne sous l'appel à render @article.comments
dans app/views/blorgh/articles/show.html.erb
:
<%= render "blorgh/comments/form" %>
Ensuite, le partial que cette ligne va rendre doit exister. Créez un nouveau répertoire à app/views/blorgh/comments
et créez-y un nouveau fichier appelé _form.html.erb
qui contient ce contenu pour créer le partial requis :
html+erb
<h3>Nouveau commentaire</h3>
<%= form_with model: [@article, @article.comments.build] do |form| %>
<p>
<%= form.label :text %><br>
<%= form.text_area :text %>
</p>
<%= form.submit %>
<% end %>
Lorsque ce formulaire est soumis, il va tenter d'effectuer une requête POST
vers une route /articles/:article_id/comments
à l'intérieur du moteur. Cette route n'existe pas pour le moment, mais peut être créée en modifiant la ligne resources :articles
dans config/routes.rb
par ces lignes :
resources :articles do
resources :comments
end
Cela crée une route imbriquée pour les commentaires, ce dont le formulaire a besoin.
La route existe maintenant, mais le contrôleur vers lequel cette route va n'existe pas. Pour le créer, exécutez cette commande à partir de la racine du moteur :
$ bin/rails generate controller comments
Cela générera les éléments suivants :
create app/controllers/blorgh/comments_controller.rb
invoke erb
exist app/views/blorgh/comments
invoke test_unit
create test/controllers/blorgh/comments_controller_test.rb
invoke helper
create app/helpers/blorgh/comments_helper.rb
invoke test_unit
Le formulaire va effectuer une requête POST
vers /articles/:article_id/comments
, qui correspondra à l'action create
dans Blorgh::CommentsController
. Cette action doit être créée, ce qui peut être fait en ajoutant les lignes suivantes à la définition de classe dans app/controllers/blorgh/comments_controller.rb
:
def create
@article = Article.find(params[:article_id])
@comment = @article.comments.create(comment_params)
flash[:notice] = "Le commentaire a été créé !"
redirect_to articles_path
end
private
def comment_params
params.require(:comment).permit(:text)
end
C'est la dernière étape nécessaire pour faire fonctionner le formulaire de nouveau commentaire. Cependant, l'affichage des commentaires n'est pas encore tout à fait correct. Si vous créez un commentaire maintenant, vous verrez cette erreur :
Missing partial blorgh/comments/_comment with {:handlers=>[:erb, :builder],
:formats=>[:html], :locale=>[:en, :en]}. Searched in: *
"/Users/ryan/Sites/side_projects/blorgh/test/dummy/app/views" *
"/Users/ryan/Sites/side_projects/blorgh/app/views"
Le moteur ne parvient pas à trouver la partial requise pour afficher les commentaires. Rails recherche d'abord dans le répertoire app/views
de l'application (test/dummy
) puis dans le répertoire app/views
du moteur. Lorsqu'il ne la trouve pas, il génère cette erreur. Le moteur sait qu'il doit chercher blorgh/comments/_comment
car l'objet modèle qu'il reçoit provient de la classe Blorgh::Comment
.
Cette partial sera responsable de l'affichage uniquement du texte du commentaire, pour l'instant. Créez un nouveau fichier à app/views/blorgh/comments/_comment.html.erb
et ajoutez cette ligne à l'intérieur :
<%= comment_counter + 1 %>. <%= comment.text %>
La variable locale comment_counter
nous est donnée par l'appel <%= render @article.comments %>
, qui la définit automatiquement et incrémente le compteur à mesure qu'il itère à travers chaque commentaire. Elle est utilisée dans cet exemple pour afficher un petit numéro à côté de chaque commentaire lorsqu'il est créé.
Cela complète la fonction de commentaire du moteur de blog. Maintenant, il est temps de l'utiliser dans une application.
4 Intégration dans une application
Utiliser un moteur dans une application est très facile. Cette section explique comment monter le moteur dans une application et la configuration initiale requise, ainsi que la liaison du moteur à une classe User
fournie par l'application pour fournir la propriété des articles et des commentaires dans le moteur.
4.1 Monter le moteur
Tout d'abord, le moteur doit être spécifié dans le Gemfile
de l'application. S'il n'y a pas d'application disponible pour tester cela, en générer une en utilisant la commande rails new
en dehors du répertoire du moteur comme ceci :
$ rails new unicorn
Généralement, spécifier le moteur dans le Gemfile
se ferait en le spécifiant comme une gemme normale et quotidienne.
gem 'devise'
Cependant, parce que vous développez le moteur blorgh
sur votre machine locale, vous devrez spécifier l'option :path
dans votre Gemfile
:
gem 'blorgh', path: 'engines/blorgh'
Ensuite, exécutez bundle
pour installer la gemme.
Comme décrit précédemment, en plaçant la gemme dans le Gemfile
, elle sera chargée lorsque Rails sera chargé. Elle requerra d'abord lib/blorgh.rb
du moteur, puis lib/blorgh/engine.rb
, qui est le fichier qui définit les principales fonctionnalités du moteur.
Pour rendre la fonctionnalité du moteur accessible depuis une application, il doit être monté dans le fichier config/routes.rb
de cette application :
mount Blorgh::Engine, at: "/blog"
Cette ligne montera le moteur à /blog
dans l'application. Il sera accessible à http://localhost:3000/blog
lorsque l'application sera exécutée avec bin/rails server
.
NOTE : D'autres moteurs, comme Devise, gèrent cela un peu différemment en vous obligeant à spécifier des helpers personnalisés (comme devise_for
) dans les routes. Ces helpers font exactement la même chose, ils montent des parties de la fonctionnalité du moteur à un chemin prédéfini qui peut être personnalisé.
4.2 Configuration du moteur
Le moteur contient des migrations pour les tables blorgh_articles
et blorgh_comments
qui doivent être créées dans la base de données de l'application afin que les modèles du moteur puissent les interroger correctement. Pour copier ces migrations dans l'application, exécutez la commande suivante à partir de la racine de l'application :
$ bin/rails blorgh:install:migrations
Si vous avez plusieurs moteurs qui ont besoin de migrations copiées, utilisez railties:install:migrations
à la place :
$ bin/rails railties:install:migrations
Vous pouvez spécifier un chemin personnalisé dans le moteur source pour les migrations en spécifiant MIGRATIONS_PATH.
$ bin/rails railties:install:migrations MIGRATIONS_PATH=db_blourgh
Si vous avez plusieurs bases de données, vous pouvez également spécifier la base de données cible en spécifiant DATABASE.
$ bin/rails railties:install:migrations DATABASE=animals
Cette commande, lorsqu'elle est exécutée pour la première fois, copiera toutes les migrations du moteur. Lorsqu'elle est exécutée la fois suivante, elle ne copiera que les migrations qui n'ont pas encore été copiées. La première exécution de cette commande affichera quelque chose comme ceci :
Copied migration [timestamp_1]_create_blorgh_articles.blorgh.rb from blorgh
Copied migration [timestamp_2]_create_blorgh_comments.blorgh.rb from blorgh
Le premier timestamp ([timestamp_1]
) sera l'heure actuelle, et le deuxième timestamp ([timestamp_2]
) sera l'heure actuelle plus une seconde. La raison de cela est que les migrations du moteur sont exécutées après toutes les migrations existantes dans l'application.
Pour exécuter ces migrations dans le contexte de l'application, exécutez simplement bin/rails db:migrate
. Lorsque vous accédez au moteur via http://localhost:3000/blog
, les articles seront vides. Cela est dû au fait que la table créée dans l'application est différente de celle créée dans le moteur. Allez-y, jouez avec le moteur nouvellement monté. Vous constaterez que c'est le même que lorsqu'il était seulement un moteur.
Si vous souhaitez exécuter les migrations uniquement à partir d'un seul moteur, vous pouvez le faire en spécifiant SCOPE
:
$ bin/rails db:migrate SCOPE=blorgh
Cela peut être utile si vous souhaitez revenir en arrière sur les migrations du moteur avant de le supprimer. Pour revenir en arrière sur toutes les migrations du moteur blorgh, vous pouvez exécuter du code tel que :
$ bin/rails db:migrate SCOPE=blorgh VERSION=0
4.3 Utilisation d'une classe fournie par l'application
4.3.1 Utilisation d'un modèle fourni par l'application
Lorsqu'un moteur est créé, il peut vouloir utiliser des classes spécifiques d'une application pour établir des liens entre les éléments du moteur et les éléments de l'application. Dans le cas du moteur blorgh
, il serait logique que les articles et les commentaires aient des auteurs.
Une application typique pourrait avoir une classe User
qui serait utilisée pour représenter les auteurs d'un article ou d'un commentaire. Mais il pourrait y avoir un cas où l'application appelle cette classe différemment, par exemple Person
. Pour cette raison, le moteur ne doit pas coder en dur des associations spécifiques pour une classe User
.
Pour simplifier les choses dans ce cas, l'application aura une classe appelée User
qui représente les utilisateurs de l'application (nous verrons comment rendre cela configurable plus loin). Elle peut être générée en utilisant cette commande à l'intérieur de l'application :
$ bin/rails generate model user name:string
La commande bin/rails db:migrate
doit être exécutée ici pour s'assurer que notre application dispose de la table users
pour une utilisation future.
De plus, pour simplifier les choses, le formulaire des articles aura un nouveau champ de texte appelé author_name
, où les utilisateurs peuvent choisir d'indiquer leur nom. Le moteur prendra ensuite ce nom et créera soit un nouvel objet User
à partir de celui-ci, soit en trouvera un qui a déjà ce nom. Le moteur associera ensuite l'article à l'objet User
trouvé ou créé.
Tout d'abord, le champ de texte author_name
doit être ajouté à la partial app/views/blorgh/articles/_form.html.erb
à l'intérieur du moteur. Cela peut être ajouté au-dessus du champ title
avec ce code :
<div class="field">
<%= form.label :author_name %><br>
<%= form.text_field :author_name %>
</div>
Ensuite, nous devons mettre à jour notre méthode Blorgh::ArticlesController#article_params
pour autoriser le nouveau paramètre du formulaire :
def article_params
params.require(:article).permit(:title, :text, :author_name)
end
Le modèle Blorgh::Article
devrait ensuite contenir du code pour convertir le champ author_name
en un véritable objet User
et l'associer en tant qu'auteur de cet article avant que l'article ne soit enregistré. Il devra également avoir un attr_accessor
configuré pour ce champ, afin que les méthodes setter et getter soient définies pour celui-ci.
Pour faire tout cela, vous devrez ajouter l'attr_accessor
pour author_name
, l'association pour l'auteur et l'appel before_validation
dans app/models/blorgh/article.rb
. L'association author
sera codée en dur pour la classe User
pour le moment.
```ruby
mattr_accessor :author_class
def self.author_class @@author_class.constantize end ```
This way, whenever Blorgh.author_class
is called, it will automatically call constantize
on the saved value.
4.3.2 Configuring the Engine in the Application
To configure the engine in the application, create an initializer file in the application's config/initializers
directory. For example, create a file called blorgh.rb
and add the following code:
Blorgh.author_class = "User"
This sets the author_class
configuration setting to "User"
. Replace "User"
with the appropriate class name if needed.
4.3.3 Overriding Engine Views
To override the engine's views with custom views in the application, create a directory called blorgh
inside the application's app/views
directory. Then, create the same directory structure as the engine's views inside the blorgh
directory. For example, to override the show.html.erb
view, create the file app/views/blorgh/articles/show.html.erb
and add the desired custom code.
4.3.4 Overriding Engine Controllers
To override the engine's controllers with custom controllers in the application, create a directory called blorgh
inside the application's app/controllers
directory. Then, create the same directory structure as the engine's controllers inside the blorgh
directory. For example, to override the ArticlesController
, create the file app/controllers/blorgh/articles_controller.rb
and define the custom controller code.
4.3.5 Overriding Engine Models
To override the engine's models with custom models in the application, create a directory called blorgh
inside the application's app/models
directory. Then, create the same directory structure as the engine's models inside the blorgh
directory. For example, to override the Article
model, create the file app/models/blorgh/article.rb
and define the custom model code.
4.3.6 Overriding Engine Routes
To override the engine's routes with custom routes in the application, create a file called blorgh.rb
inside the application's config/routes
directory. In this file, define the custom routes using the draw
method. For example:
Rails.application.routes.draw do
mount Blorgh::Engine, at: "/blog"
get "/articles", to: "custom_articles#index"
end
This mounts the engine at the /blog
path and adds a custom route for the /articles
path.
4.3.7 Overriding Engine Migrations
To override the engine's migrations with custom migrations in the application, create a directory called blorgh
inside the application's db/migrate
directory. Then, copy the desired engine migration files into the blorgh
directory. You can modify the copied migration files as needed.
4.3.8 Running Engine Migrations
To run the engine's migrations in the application, use the following command:
$ bin/rails db:migrate
This will run all pending migrations, including the engine's migrations.
4.3.9 Running Engine Tests
To run the engine's tests in the application, use the following command:
$ bin/rails test
This will run all tests, including the engine's tests.
4.3.10 Running Engine Generators
To run the engine's generators in the application, use the following command:
$ bin/rails generate blorgh:generator_name
Replace generator_name
with the name of the desired generator.
4.3.11 Running Engine Tasks
To run the engine's tasks in the application, use the following command:
$ bin/rails blorgh:task_name
Replace task_name
with the name of the desired task.
4.3.12 Running Engine Rake Tasks
To run the engine's Rake tasks in the application, use the following command:
$ bin/rake blorgh:task_name
Replace task_name
with the name of the desired task.
4.3.13 Running Engine Console
To access the engine's console in the application, use the following command:
$ bin/rails console
This will open the Rails console with access to the engine's models and functionality.
ruby
def self.author_class
@@author_class.constantize
end
Cela transforme ensuite le code ci-dessus pour set_author
en ceci :
self.author = Blorgh.author_class.find_or_create_by(name: author_name)
Résultant en quelque chose de plus court et plus implicite dans son comportement. La méthode author_class
doit toujours renvoyer un objet Class
.
Puisque nous avons modifié la méthode author_class
pour renvoyer une Class
au lieu d'une String
, nous devons également modifier notre définition belongs_to
dans le modèle Blorgh::Article
:
belongs_to :author, class_name: Blorgh.author_class.to_s
Pour définir ce paramètre de configuration dans l'application, un initialiseur doit être utilisé. En utilisant un initialiseur, la configuration sera mise en place avant le démarrage de l'application et appelle les modèles du moteur, qui peuvent dépendre de l'existence de ce paramètre de configuration.
Créez un nouvel initialiseur dans config/initializers/blorgh.rb
à l'intérieur de l'application où le moteur blorgh
est installé et mettez-y ce contenu :
Blorgh.author_class = "User"
ATTENTION : Il est très important ici d'utiliser la version String
de la classe, plutôt que la classe elle-même. Si vous utilisiez la classe, Rails tenterait de charger cette classe puis de référencer la table associée. Cela pourrait poser des problèmes si la table n'existait pas déjà. Par conséquent, une String
doit être utilisée, puis convertie en classe en utilisant constantize
dans le moteur plus tard.
Allez-y et essayez de créer un nouvel article. Vous verrez que cela fonctionne exactement de la même manière qu'auparavant, sauf que cette fois-ci, le moteur utilise le paramètre de configuration dans config/initializers/blorgh.rb
pour savoir quelle est la classe.
Il n'y a maintenant aucune dépendance stricte sur la classe, seulement sur l'API de la classe. Le moteur demande simplement à cette classe de définir une méthode find_or_create_by
qui renvoie un objet de cette classe, à associer à un article lors de sa création. Cet objet, bien sûr, doit avoir une sorte d'identifiant par lequel il peut être référencé.
4.3.14 Configuration générale du moteur
Dans un moteur, il peut arriver un moment où vous souhaitez utiliser des choses telles que des initialiseurs, l'internationalisation ou d'autres options de configuration. La bonne nouvelle, c'est que ces choses sont tout à fait possibles, car un moteur Rails partage en grande partie la même fonctionnalité qu'une application Rails. En fait, la fonctionnalité d'une application Rails est en réalité un sur-ensemble de ce que fournissent les moteurs !
Si vous souhaitez utiliser un initialiseur - du code qui doit s'exécuter avant le chargement du moteur - l'endroit pour le faire est le dossier config/initializers
. La fonctionnalité de ce répertoire est expliquée dans la section Initializers du guide de configuration, et fonctionne exactement de la même manière que le répertoire config/initializers
à l'intérieur d'une application. Il en va de même si vous souhaitez utiliser un initialiseur standard.
Pour les localisations, placez simplement les fichiers de localisation dans le répertoire config/locales
, comme vous le feriez dans une application.
5 Tester un moteur
Lorsqu'un moteur est généré, une plus petite application fictive est créée à l'intérieur de celui-ci à test/dummy
. Cette application est utilisée comme point de montage pour le moteur, afin de rendre les tests du moteur extrêmement simples. Vous pouvez étendre cette application en générant des contrôleurs, des modèles ou des vues depuis le répertoire, puis les utiliser pour tester votre moteur.
Le répertoire test
doit être traité comme un environnement de test Rails classique, permettant les tests unitaires, fonctionnels et d'intégration.
5.1 Tests fonctionnels
Un point à prendre en considération lors de l'écriture de tests fonctionnels est que les tests vont s'exécuter sur une application - l'application test/dummy
- plutôt que sur votre moteur. Cela est dû à la configuration de l'environnement de test ; un moteur a besoin d'une application comme hôte pour tester sa fonctionnalité principale, en particulier les contrôleurs. Cela signifie que si vous deviez faire un GET
typique vers un contrôleur dans un test fonctionnel du contrôleur comme ceci :
module Blorgh
class FooControllerTest < ActionDispatch::IntegrationTest
include Engine.routes.url_helpers
def test_index
get foos_url
# ...
end
end
end
Cela peut ne pas fonctionner correctement. C'est parce que l'application ne sait pas comment router ces requêtes vers le moteur à moins que vous ne lui disiez comment. Pour ce faire, vous devez définir la variable d'instance @routes
sur l'ensemble de routes du moteur dans votre code de configuration :
module Blorgh
class FooControllerTest < ActionDispatch::IntegrationTest
include Engine.routes.url_helpers
setup do
@routes = Engine.routes
end
def test_index
get foos_url
# ...
end
end
end
Cela indique à l'application que vous souhaitez toujours effectuer une requête GET
vers l'action index
de ce contrôleur, mais vous souhaitez utiliser la route du moteur pour y accéder, plutôt que celle de l'application.
Cela garantit également que les assistants d'URL du moteur fonctionneront comme prévu dans vos tests.
6 Amélioration de la fonctionnalité du moteur
Cette section explique comment ajouter et/ou remplacer la fonctionnalité MVC du moteur dans l'application principale de Rails.
6.1 Remplacement des modèles et des contrôleurs
Les modèles et les contrôleurs du moteur peuvent être réouverts par l'application parente pour les étendre ou les décorer.
Les remplacements peuvent être organisés dans un répertoire dédié app/overrides
, ignoré par l'autoloader, et préchargés dans un rappel to_prepare
:
# config/application.rb
module MyApp
class Application < Rails::Application
# ...
overrides = "#{Rails.root}/app/overrides"
Rails.autoloaders.main.ignore(overrides)
config.to_prepare do
Dir.glob("#{overrides}/**/*_override.rb").sort.each do |override|
load override
end
end
end
end
6.1.1 Réouverture des classes existantes à l'aide de class_eval
Par exemple, pour remplacer le modèle du moteur
# Blorgh/app/models/blorgh/article.rb
module Blorgh
class Article < ApplicationRecord
# ...
end
end
vous créez simplement un fichier qui réouvre cette classe :
# MyApp/app/overrides/models/blorgh/article_override.rb
Blorgh::Article.class_eval do
# ...
end
Il est très important que le remplacement réouvre la classe ou le module. Utiliser les mots-clés class
ou module
les définirait s'ils n'étaient pas déjà en mémoire, ce qui serait incorrect car la définition se trouve dans le moteur. En utilisant class_eval
comme indiqué ci-dessus, vous vous assurez de les réouvrir.
6.1.2 Réouverture des classes existantes à l'aide de ActiveSupport::Concern
Utiliser Class#class_eval
est idéal pour les ajustements simples, mais pour des modifications de classe plus complexes, vous voudrez peut-être envisager d'utiliser ActiveSupport::Concern
. ActiveSupport::Concern gère l'ordre de chargement des modules et des classes dépendantes interconnectées au moment de l'exécution, ce qui vous permet de moduler considérablement votre code.
Ajout de Article#time_since_created
et remplacement de Article#summary
:
# MyApp/app/models/blorgh/article.rb
class Blorgh::Article < ApplicationRecord
include Blorgh::Concerns::Models::Article
def time_since_created
Time.current - created_at
end
def summary
"#{title} - #{truncate(text)}"
end
end
# Blorgh/app/models/blorgh/article.rb
module Blorgh
class Article < ApplicationRecord
include Blorgh::Concerns::Models::Article
end
end
# Blorgh/lib/concerns/models/article.rb
module Blorgh::Concerns::Models::Article
extend ActiveSupport::Concern
# `included do` permet d'évaluer le bloc dans le contexte
# dans lequel le module est inclus (c'est-à-dire Blorgh::Article),
# plutôt que dans le module lui-même.
included do
attr_accessor :author_name
belongs_to :author, class_name: "User"
before_validation :set_author
private
def set_author
self.author = User.find_or_create_by(name: author_name)
end
end
def summary
"#{title}"
end
module ClassMethods
def some_class_method
'some class method string'
end
end
end
6.2 Autoloading et moteurs
Veuillez consulter le guide Autoloading and Reloading Constants pour plus d'informations sur l'autoloading et les moteurs.
6.3 Remplacement des vues
Lorsque Rails recherche une vue à rendre, il recherche d'abord dans le répertoire app/views
de l'application. S'il ne la trouve pas là, il vérifie dans les répertoires app/views
de tous les moteurs qui ont ce répertoire.
Lorsque l'application est invitée à rendre la vue pour l'action index
du contrôleur Blorgh::ArticlesController
, elle recherche d'abord le chemin app/views/blorgh/articles/index.html.erb
dans l'application. Si elle ne le trouve pas, elle le recherche dans le moteur.
Vous pouvez remplacer cette vue dans l'application en créant simplement un nouveau fichier à app/views/blorgh/articles/index.html.erb
. Ensuite, vous pouvez modifier complètement ce que cette vue produirait normalement.
Essayez maintenant en créant un nouveau fichier à app/views/blorgh/articles/index.html.erb
et en y mettant ce contenu :
<h1>Articles</h1>
<%= link_to "New Article", new_article_path %>
<% @articles.each do |article| %>
<h2><%= article.title %></h2>
<small>By <%= article.author %></small>
<%= simple_format(article.text) %>
<hr>
<% end %>
6.4 Routes
Les routes à l'intérieur d'un moteur sont isolées de l'application par défaut. Cela est réalisé par l'appel à isolate_namespace
à l'intérieur de la classe Engine
. Cela signifie essentiellement que l'application et ses moteurs peuvent avoir des routes portant le même nom et qu'elles ne se chevaucheront pas.
Les routes à l'intérieur d'un moteur sont définies sur la classe Engine
dans config/routes.rb
, comme ceci :
Blorgh::Engine.routes.draw do
resources :articles
end
En ayant des routes isolées comme celles-ci, si vous souhaitez créer un lien vers une zone d'un moteur à partir de l'application, vous devrez utiliser la méthode de proxy de routage du moteur. Les appels aux méthodes de routage normales telles que articles_path
peuvent finir par aller à des emplacements indésirables si l'application et le moteur ont tous deux une telle aide définie.
Par exemple, l'exemple suivant irait vers articles_path
de l'application si ce modèle était rendu à partir de l'application, ou vers articles_path
du moteur s'il était rendu à partir du moteur :
erb
<%= link_to "Articles de blog", articles_path %>
Pour que cette route utilise toujours la méthode d'aide de routage articles_path
du moteur,
nous devons appeler la méthode sur la méthode proxy de routage qui porte le même nom que
le moteur.
<%= link_to "Articles de blog", blorgh.articles_path %>
Si vous souhaitez faire référence à l'application à l'intérieur du moteur de manière similaire, utilisez
l'aide main_app
:
<%= link_to "Accueil", main_app.root_path %>
Si vous utilisez cela à l'intérieur d'un moteur, cela ira toujours à la
racine de l'application. Si vous omettez l'appel à la méthode proxy de routage main_app
,
cela pourrait éventuellement aller à la racine du moteur ou de l'application,
selon l'endroit où il a été appelé.
Si un modèle rendu à partir d'un moteur tente d'utiliser l'une des
méthodes d'aide de routage de l'application, cela peut entraîner un appel à une méthode non définie.
Si vous rencontrez un tel problème, assurez-vous de ne pas essayer d'appeler les
méthodes de routage de l'application sans le préfixe main_app
à partir du
moteur.
6.5 Ressources
Les ressources à l'intérieur d'un moteur fonctionnent de la même manière que dans une application complète. Parce que
la classe du moteur hérite de Rails::Engine
, l'application saura
rechercher les ressources dans les répertoires app/assets
et lib/assets
du moteur.
Comme tous les autres composants d'un moteur, les ressources doivent être regroupées.
Cela signifie que si vous avez une ressource appelée style.css
, elle doit être placée dans
app/assets/stylesheets/[nom du moteur]/style.css
, plutôt que
app/assets/stylesheets/style.css
. Si cette ressource n'est pas regroupée, il y a
une possibilité que l'application hôte ait une ressource portant le même nom, auquel cas la ressource de l'application
prendrait le dessus et celle du moteur serait ignorée.
Imaginez que vous ayez une ressource située à
app/assets/stylesheets/blorgh/style.css
. Pour inclure cette ressource dans une
application, utilisez simplement stylesheet_link_tag
et référencez la ressource comme si elle
était à l'intérieur du moteur :
<%= stylesheet_link_tag "blorgh/style.css" %>
Vous pouvez également spécifier ces ressources en tant que dépendances d'autres ressources en utilisant des déclarations de dépendance de l'Asset Pipeline dans les fichiers traités :
/*
*= require blorgh/style
*/
N'oubliez pas qu'en utilisant des langages comme Sass ou CoffeeScript, vous
devriez ajouter la bibliothèque correspondante au fichier .gemspec
de votre moteur.
6.6 Séparation des ressources et précompilation
Il y a des situations où les ressources de votre moteur ne sont pas nécessaires pour
l'application hôte. Par exemple, supposons que vous ayez créé une fonctionnalité d'administration
qui n'existe que pour votre moteur. Dans ce cas, l'application hôte n'a pas besoin de
demander admin.css
ou admin.js
. Seul le modèle d'administration du gemme a besoin
de ces ressources. Il n'a pas de sens pour l'application hôte d'inclure
"blorgh/admin.css"
dans ses feuilles de style. Dans cette situation, vous devriez
définir explicitement ces ressources pour la précompilation. Cela indique à Sprockets d'ajouter
les ressources de votre moteur lorsque bin/rails assets:precompile
est déclenché.
Vous pouvez définir les ressources pour la précompilation dans engine.rb
:
initializer "blorgh.assets.precompile" do |app|
app.config.assets.precompile += %w( admin.js admin.css )
end
Pour plus d'informations, consultez le guide de l'Asset Pipeline.
6.7 Autres dépendances de gemmes
Les dépendances de gemmes à l'intérieur d'un moteur doivent être spécifiées dans le fichier .gemspec
à la racine du moteur. La raison en est que le moteur peut être installé en tant que
gemme. Si les dépendances étaient spécifiées dans le Gemfile
, elles ne seraient pas
reconnues par une installation de gemme traditionnelle et ne seraient donc pas installées,
ce qui provoquerait un dysfonctionnement du moteur.
Pour spécifier une dépendance qui doit être installée avec le moteur lors d'une
installation de gemme traditionnelle, spécifiez-la à l'intérieur du bloc Gem::Specification
dans le fichier .gemspec
du moteur :
s.add_dependency "moo"
Pour spécifier une dépendance qui ne doit être installée qu'en tant que dépendance de développement de l'application, spécifiez-la comme ceci :
s.add_development_dependency "moo"
Les deux types de dépendances seront installés lorsque bundle install
est exécuté à l'intérieur
de l'application. Les dépendances de développement pour le gemme ne seront utilisées
que lorsque le développement et les tests du moteur sont en cours d'exécution.
Notez que si vous souhaitez exiger immédiatement des dépendances lorsque le moteur est requis, vous devez les exiger avant l'initialisation du moteur. Par exemple :
require "other_engine/engine"
require "yet_another_engine/engine"
module MyEngine
class Engine < ::Rails::Engine
end
end
7 Hooks de chargement et de configuration
Le code Rails peut souvent être référencé lors du chargement d'une application. Rails est responsable de l'ordre de chargement de ces frameworks, donc lorsque vous chargez des frameworks, tels que ActiveRecord::Base
, prématurément, vous violez un contrat implicite que votre application a avec Rails. De plus, en chargeant du code tel que ActiveRecord::Base
au démarrage de votre application, vous chargez des frameworks entiers qui peuvent ralentir le temps de démarrage et causer des conflits avec l'ordre de chargement et le démarrage de votre application.
Les hooks de chargement et de configuration sont l'API qui vous permet de vous brancher sur ce processus d'initialisation sans violer le contrat de chargement avec Rails. Cela permet également de réduire la dégradation des performances de démarrage et d'éviter les conflits.
7.1 Éviter le chargement des frameworks Rails
Étant donné que Ruby est un langage dynamique, certains codes entraîneront le chargement de différents frameworks Rails. Prenons par exemple ce fragment de code :
ActiveRecord::Base.include(MyActiveRecordHelper)
Ce fragment signifie que lorsque ce fichier est chargé, il rencontrera ActiveRecord::Base
. Cette rencontre amène Ruby à rechercher la définition de cette constante et à la charger. Cela entraîne le chargement complet du framework Active Record au démarrage.
ActiveSupport.on_load
est un mécanisme qui peut être utilisé pour différer le chargement du code jusqu'à ce qu'il soit réellement nécessaire. Le fragment ci-dessus peut être modifié comme suit :
ActiveSupport.on_load(:active_record) do
include MyActiveRecordHelper
end
Ce nouveau fragment inclura uniquement MyActiveRecordHelper
lorsque ActiveRecord::Base
sera chargé.
7.2 Quand les hooks sont-ils appelés ?
Dans le framework Rails, ces hooks sont appelés lorsqu'une bibliothèque spécifique est chargée. Par exemple, lorsque ActionController::Base
est chargé, le hook :action_controller_base
est appelé. Cela signifie que tous les appels ActiveSupport.on_load
avec des hooks :action_controller_base
seront appelés dans le contexte de ActionController::Base
(ce qui signifie que self
sera un ActionController::Base
).
7.3 Modification du code pour utiliser les hooks de chargement
La modification du code est généralement simple. Si vous avez une ligne de code qui fait référence à un framework Rails tel que ActiveRecord::Base
, vous pouvez envelopper ce code dans un hook de chargement.
Modification des appels à include
ActiveRecord::Base.include(MyActiveRecordHelper)
devient
ActiveSupport.on_load(:active_record) do
# self fait référence à ActiveRecord::Base ici,
# nous pouvons donc appeler .include
include MyActiveRecordHelper
end
Modification des appels à prepend
ActionController::Base.prepend(MyActionControllerHelper)
devient
ActiveSupport.on_load(:action_controller_base) do
# self fait référence à ActionController::Base ici,
# nous pouvons donc appeler .prepend
prepend MyActionControllerHelper
end
Modification des appels aux méthodes de classe
ActiveRecord::Base.include_root_in_json = true
devient
ActiveSupport.on_load(:active_record) do
# self fait référence à ActiveRecord::Base ici
self.include_root_in_json = true
end
7.4 Hooks de chargement disponibles
Voici les hooks de chargement que vous pouvez utiliser dans votre propre code. Pour vous brancher sur le processus d'initialisation de l'une des classes suivantes, utilisez le hook disponible.
Classe | Hook |
---|---|
ActionCable |
action_cable |
ActionCable::Channel::Base |
action_cable_channel |
ActionCable::Connection::Base |
action_cable_connection |
ActionCable::Connection::TestCase |
action_cable_connection_test_case |
ActionController::API |
action_controller_api |
ActionController::API |
action_controller |
ActionController::Base |
action_controller_base |
ActionController::Base |
action_controller |
ActionController::TestCase |
action_controller_test_case |
ActionDispatch::IntegrationTest |
action_dispatch_integration_test |
ActionDispatch::Response |
action_dispatch_response |
ActionDispatch::Request |
action_dispatch_request |
ActionDispatch::SystemTestCase |
action_dispatch_system_test_case |
ActionMailbox::Base |
action_mailbox |
ActionMailbox::InboundEmail |
action_mailbox_inbound_email |
ActionMailbox::Record |
action_mailbox_record |
ActionMailbox::TestCase |
action_mailbox_test_case |
ActionMailer::Base |
action_mailer |
ActionMailer::TestCase |
action_mailer_test_case |
ActionText::Content |
action_text_content |
ActionText::Record |
action_text_record |
ActionText::RichText |
action_text_rich_text |
ActionText::EncryptedRichText |
action_text_encrypted_rich_text |
ActionView::Base |
action_view |
ActionView::TestCase |
action_view_test_case |
ActiveJob::Base |
active_job |
ActiveJob::TestCase |
active_job_test_case |
ActiveRecord::Base |
active_record |
ActiveRecord::TestFixtures |
active_record_fixtures |
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter |
active_record_postgresqladapter |
ActiveRecord::ConnectionAdapters::Mysql2Adapter |
active_record_mysql2adapter |
ActiveRecord::ConnectionAdapters::TrilogyAdapter |
active_record_trilogyadapter |
ActiveRecord::ConnectionAdapters::SQLite3Adapter |
active_record_sqlite3adapter |
ActiveStorage::Attachment |
active_storage_attachment |
ActiveStorage::VariantRecord |
active_storage_variant_record |
ActiveStorage::Blob |
active_storage_blob |
ActiveStorage::Record |
active_storage_record |
ActiveSupport::TestCase |
active_support_test_case |
i18n |
i18n |
7.5 Hooks de configuration disponibles
Les hooks de configuration ne se branchent sur aucun framework en particulier, mais s'exécutent plutôt dans le contexte de l'application entière.
Hook | Cas d'utilisation |
---|---|
before_configuration |
Premier bloc configurable à exécuter. Appelé avant l'exécution de tout initialisateur. |
before_initialize |
Deuxième bloc configurable à exécuter. Appelé avant l'initialisation des frameworks. |
before_eager_load |
Troisième bloc configurable à exécuter. Ne s'exécute pas si config.eager_load est défini sur false. |
after_initialize |
Dernier bloc configurable à exécuter. Appelé après l'initialisation des frameworks. |
Les hooks de configuration peuvent être appelés dans la classe Engine.
module Blorgh
class Engine < ::Rails::Engine
config.before_configuration do
puts 'Je suis appelé avant tout initialisateur'
end
end
end
Retour d'information
Vous êtes encouragé à contribuer à l'amélioration de la qualité de ce guide.
Veuillez contribuer si vous trouvez des fautes de frappe ou des erreurs factuelles. Pour commencer, vous pouvez lire notre contribution à la documentation section.
Vous pouvez également trouver du contenu incomplet ou des informations qui ne sont pas à jour. Veuillez ajouter toute documentation manquante pour la version principale. Assurez-vous de vérifier Edge Guides d'abord pour vérifier si les problèmes ont déjà été résolus ou non sur la branche principale. Consultez les Directives des guides Ruby on Rails pour le style et les conventions.
Si pour une raison quelconque vous repérez quelque chose à corriger mais ne pouvez pas le faire vous-même, veuillez ouvrir un problème.
Et enfin, toute discussion concernant la documentation de Ruby on Rails est la bienvenue sur le Forum officiel de Ruby on Rails.