많은 플러그인이 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에서 변경 사항을 제안하세요.