Viele Plugins definieren 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 Neustart des Servers
- Die richtige Reihenfolge der
require-Aufrufe 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-Rails-Autoloading-System stützen. Für neue Plugins ist alles, was Sie benötigen, im plugin-skeleton definiert. Dieses Thema beschreibt, wie ein bestehendes Plugin angepasst und die Konfiguration erweitert werden kann.
1. Ein Modul und eine Rails::Engine für Ihr Plugin definieren
In plugin.rb definieren Sie ein Modul für Ihr Plugin mit einem eindeutigen PLUGIN_NAME und fügen eine require_relative-Zeile hinzu, um die Engine-Datei zu laden, die wir gerade erstellen werden.
# 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, die zu beachten sind:
-
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 derplugin.rb-Datei befinden, nicht innerhalb einesafter_initialize-Blocks -
Das Ablegen der Engine in einer eigenen Datei unter
lib/ist wichtig. Die direkte Definition in derplugin.rb-Datei funktioniert nicht. (Rails verwendet die Existenz eineslib/-Verzeichnisses, um den Stamm der Engine zu bestimmen) -
Der Dateipfad sollte den Modulnamen enthalten, gemäß den Zeitwerk-Regeln
-
Der
engine_namewird als Präfix für Rake-Aufgaben und alle vom Engine definierten Routen verwendet (
Rails Doku) -
isolate_namespacehilft zu verhindern, dass Dinge zwischen dem Kern und dem Plugin durchsickern (
Rails Doku)
2. Ruby-Dateien in der korrekten Verzeichnisstruktur definieren
Die Engine lädt nun automatisch alle Dateien in {plugin}/app/{type}/*. Zum Beispiel können wir 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
Dieser wird nun automatisch geladen, wann immer etwas in Rails versucht, auf ::MyPluginModule::MyController zuzugreifen. Um Dinge zu testen, versuchen Sie, auf diese Klasse über die Rails-Konsole zuzugreifen.
Damit das Autoloading 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 der Server neu gestartet werden muss. 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 hinzufügen. Das häufigste Beispiel ist das lib/-Verzeichnis in einem Plugin.
Ändern Sie Ihre Engine-Definition, um lib/ zu den automatisch ladbaren 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 jetzt wird jede Referenz auf ::MyPluginModule::SomeLibModule das Modul automatisch aus dieser Datei laden.
5. Profitieren!
Alle diese Dateien werden nun automatisch ohne bewusste require-Aufrufe geladen. Ä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.