多くのプラグインでは、plugin.rb 内に多くのクラス定義を含めたり、require_relative を使用して Ruby ファイルを読み込んだりします。これは機能しますが、いくつかの欠点があります。
- 開発中の変更の自動リロードができない。変更にはサーバーの完全な再起動が必要。
requireの呼び出しを正しい順序にするのが難しい場合がある。after_initializeブロックの外でrequireされている場合、他の自動ロードされたクラス/モジュールが利用できない可能性がある。
解決策があります!プラグインは標準の Rails 自動ロードシステムを利用できます。新しいプラグインの場合、必要なものはすべて plugin-skeleton に定義されています。このトピックでは、既存のプラグインを適応させ、設定を拡張する方法を説明します。
1. プラグインのモジュールと Rails::Engine を定義する
plugin.rb で、一意の PLUGIN_NAME を持つプラグインのモジュールを定義し、これから作成するエンジンファイルを読み込む require_relative 行を追加します。
# name: my-plugin-name
# ...
module ::MyPluginModule
PLUGIN_NAME = "my-plugin-name"
end
require_relative "lib/my_plugin_module/engine"
次に {plugin}/lib/my_plugin_module/engine.rb を作成します。
module ::MyPluginModule
class Engine < ::Rails::Engine
engine_name PLUGIN_NAME
isolate_namespace MyPluginModule
end
end
注意すべき重要な点:
-
plugin.rbでは、ルート名前空間に定義するためにモジュール名の前に::を含める必要があります(そうしないと、Plugin::Instanceの下に定義されます)。 -
require_relative "lib/.../engine"は、after_initializeブロック内ではなく、plugin.rbファイルのルートに配置する必要があります。 -
エンジンを
lib/の下の独自のファイルに配置することが重要です。plugin.rbファイルで直接定義しても機能しません。(Rails はlib/ディレクトリの存在を使用してエンジンのルートを決定します) -
ファイルパスには、Zeitwerk のルール に従ってモジュール名を含める必要があります。
-
engine_nameは、Rake タスクのプレフィックスとして、またエンジンによって定義されたルートに使用されます(
Rails ドキュメント)。 -
isolate_namespaceは、コアとプラグインの間で名前が漏洩するのを防ぐのに役立ちます(
Rails ドキュメント)。
2. 正しいディレクトリ構造で Ruby ファイルを定義する
エンジンは、{plugin}/app/{type}/* のすべてのファイルを自動ロードするようになります。たとえば、コントローラーを定義できます。
{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
これにより、Rails が ::MyPluginModule::MyController にアクセスしようとするたびに自動的にロードされるようになります。テストするには、Rails コンソールからそのクラスにアクセスしてみてください。
自動ロードが正しく機能するためには、ファイルパスは Zeitwerk によって定義されたルール に従って、完全なモジュール/クラス階層と一致する必要があります。
3. プラグインのエンジンにルートを定義する
{plugin}/config/routes.rb ファイルを作成します。
MyPluginModule::Engine.routes.draw do
get "/examples" => "examples#index"
# ルートをここに定義
end
Discourse::Application.routes.draw do
mount ::MyPluginModule::Engine, at: "my-plugin"
end
このファイルはエンジンによって自動的にロードされ、サーバーを再起動せずに変更が有効になります。この場合、コントローラーアクションは /my-plugin/examples.json で利用可能になります。
4. 追加の自動ロードパスを追加する
場合によっては、自動ロード可能な Ruby ファイルの追加ディレクトリを導入したいことがあります。最も一般的な例は、プラグインの lib/ ディレクトリです。
エンジンの自動ロードパスに lib/ を追加するように、エンジン定義を変更します。
class Engine < ::Rails::Engine
engine_name PLUGIN_NAME
isolate_namespace MyPluginModule
config.autoload_paths << File.join(config.root, "lib")
end
これで、次のような lib モジュールを定義できます。
{plugin}/lib/my_plugin_module/some_lib_module.rb
module ::MyPluginModule::SomeLibModule
end
そして、::MyPluginModule::SomeLibModule への参照は、このファイルからモジュールを自動的にロードするようになります。
5. 利益!
これらのファイルはすべて、明示的な require 呼び出しなしで自動的にロードされるようになります。変更は Rails によって自動的に検出され、サーバーを再起動することなくインプレースでリロードされます。
このドキュメントはバージョン管理されています - 変更は github で提案してください。