Viele Plugins enthalten viele Klassendefinitionen in plugin.rb oder verwenden require_relative, um Ruby-Dateien zu laden. Das funktioniert, hat aber einige Nachteile:
- Keine automatische Neuladung von Änderungen in der Entwicklung. Jede Änderung erfordert einen vollständigen Serverneustart
- Die
require-Aufrufe in die richtige Reihenfolge zu bringen, kann mühsam sein - Wenn sie außerhalb des
after_initialize-Blocksrequiret werden, sind andere automatisch geladene Klassen/Module möglicherweise nicht verfügbar
Es gibt eine Lösung! Plugins können sich auf das Standard-Autoloading-System von Rails verlassen. Für neue Plugins ist alles, was Sie benötigen, im Plugin-Skeleton definiert. Dieses Thema beschreibt, wie Sie ein vorhandenes Plugin anpassen und die Konfiguration erweitern.
1. Definieren Sie ein Modul und eine Rails::Engine für Ihr Plugin
Definieren Sie in plugin.rb ein Modul für Ihr Plugin mit einem eindeutigen PLUGIN_NAME und fügen Sie eine require_relative-Zeile hinzu, um die Engine-Datei zu laden, die wir gerade erstellen.
# name: my-plugin-name
# ...
module ::MyPluginModule
PLUGIN_NAME = "my-plugin-name"
end
require_relative "lib/my_plugin_module/engine"
Erstellen Sie nun {plugin}/lib/my_plugin_module/engine.rb:
module ::MyPluginModule
class Engine < ::Rails::Engine
engine_name PLUGIN_NAME
isolate_namespace MyPluginModule
end
end
Wichtige Punkte:
-
In
plugin.rbmüssen Sie::vor Ihrem Modulnamen einfügen, um es im Stamm-Namespace zu definieren (andernfalls würde es unterPlugin::Instancedefiniert werden). -
require_relative "lib/.../engine"muss sich im Stammverzeichnis der Dateiplugin.rbbefinden, nicht innerhalb einesafter_initialize-Blocks. -
Das Platzieren der Engine in einer eigenen Datei unter
lib/ist wichtig. Die Definition direkt in der Dateiplugin.rbfunktioniert nicht. (Rails verwendet die Anwesenheit eineslib/-Verzeichnisses, um die Stammdatei der Engine zu bestimmen.) -
Der Dateipfad sollte den Modulnamen gemäß den Zeitwerk-Regeln enthalten.
-
Der
engine_namewird als Präfix für Rake-Aufgaben und alle von der Engine definierten Routen verwendet (
Rails Docs). -
isolate_namespacehilft, das Auslaufen von Dingen zwischen dem Kern und dem Plugin zu verhindern (
Rails Docs).
2. Definieren Sie Ruby-Dateien in der richtigen Verzeichnisstruktur
Die Engine lädt nun automatisch alle Dateien in {plugin}/app/{type}/*. Wir können zum Beispiel einen Controller definieren
{plugin}/app/controllers/my_plugin_module/examples_controller.rb
module ::MyPluginModule
class ExamplesController < ::ApplicationController
requires_plugin PLUGIN_NAME
def index
render json: { hello: "world" }
end
end
end
Diese wird nun automatisch geladen, wenn etwas in Rails versucht, auf ::MyPluginModule::MyController zuzugreifen. Um Dinge zu testen, versuchen Sie, von der Rails-Konsole auf diese Klasse zuzugreifen.
Damit das automatische Laden korrekt funktioniert, müssen die Dateipfade der vollständigen Modul-/Klassenhierarchie gemäß den von Zeitwerk definierten Regeln entsprechen.
3. Routen auf der Engine des Plugins definieren
Erstellen Sie eine Datei {plugin}/config/routes.rb
MyPluginModule::Engine.routes.draw do
get "/examples" => "examples#index"
# Routen hier definieren
end
Discourse::Application.routes.draw do
mount ::MyPluginModule::Engine, at: "my-plugin"
end
Diese Datei wird automatisch von der Engine geladen, und Änderungen werden wirksam, ohne dass ein Serverneustart erforderlich ist. In diesem Fall wäre die Controller-Aktion unter /my-plugin/examples.json verfügbar.
4. Weitere automatisch ladbare Pfade hinzufügen
Manchmal möchten Sie zusätzliche Verzeichnisse mit automatisch ladbaren Ruby-Dateien einführen. Das häufigste Beispiel ist das lib/-Verzeichnis in einem Plugin.
Ändern Sie Ihre Engine-Definition, um lib/ zu den Autoload-Pfaden der Engine hinzuzufügen:
class Engine < ::Rails::Engine
engine_name PLUGIN_NAME
isolate_namespace MyPluginModule
config.autoload_paths << File.join(config.root, "lib")
end
Jetzt können Sie ein Lib-Modul definieren wie
{plugin}/lib/my_plugin_module/some_lib_module.rb
module ::MyPluginModule::SomeLibModule
end
Und nun werden alle Verweise auf ::MyPluginModule::SomeLibModule das Modul automatisch aus dieser Datei laden.
5. Profitieren!
All diese Dateien werden nun automatisch geladen, ohne dass bewusste require-Aufrufe erforderlich sind. Änderungen werden automatisch von Rails erkannt und ohne Serverneustart an Ort und Stelle neu geladen.
Dieses Dokument wird versioniert - schlagen Sie Änderungen auf GitHub vor.