Muitos plugins incluem muitas definições de classe dentro de plugin.rb, ou usam require_relative para carregar arquivos ruby. Isso funciona, mas tem algumas desvantagens:
- Sem recarregamento automático de alterações em desenvolvimento. Quaisquer alterações exigem uma reinicialização completa do servidor
- Conseguir as chamadas
requirena ordem correta pode ser doloroso - Se eles forem
require’d fora do blocoafter_initialize, outras classes/módulos carregados automaticamente podem não estar disponíveis
Existe uma solução! Plugins podem usar o sistema de autoloading padrão do Rails. Para novos plugins, tudo o que você precisa está definido no plugin-skeleton. Este tópico descreve como adaptar um plugin existente e estender a configuração.
1. Defina um módulo e um Rails::Engine para seu plugin
Em plugin.rb, defina um módulo para seu plugin com um PLUGIN_NAME exclusivo e adicione uma linha require_relative para carregar o arquivo do engine que vamos criar.
# name: my-plugin-name
# ...
module ::MyPluginModule
PLUGIN_NAME = "my-plugin-name"
end
require_relative "lib/my_plugin_module/engine"
Agora crie {plugin}/lib/my_plugin_module/engine.rb:
module ::MyPluginModule
class Engine < ::Rails::Engine
engine_name PLUGIN_NAME
isolate_namespace MyPluginModule
end
end
Coisas importantes a notar:
-
Em
plugin.rb, você deve incluir::antes do nome do seu módulo para defini-lo no namespace raiz (caso contrário, ele seria definido sobPlugin::Instance) -
require_relative "lib/.../engine"deve estar na raiz do arquivoplugin.rb, não dentro de um blocoafter_initialize -
Colocar o engine em seu próprio arquivo sob
lib/é importante. Definir diretamente no arquivoplugin.rbnão funcionará. (Rails usa a presença de um diretóriolib/para determinar a raiz do engine) -
O caminho do arquivo deve incluir o nome do módulo, de acordo com as regras do Zeitwerk
-
O
engine_nameé usado como prefixo para tarefas rake e quaisquer rotas definidas pelo engine (
docs do rails) -
isolate_namespaceajuda a evitar que coisas vazem entre o núcleo e o plugin (
docs do Rails)
2. Defina arquivos ruby na estrutura de diretórios correta
O engine agora carregará automaticamente todos os arquivos em {plugin}/app/{type}/*. Por exemplo, podemos definir um controller
{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
Isso agora será carregado automaticamente sempre que algo no Rails tentar acessar ::MyPluginModule::MyController. Para testar, tente acessar essa classe do console do rails.
Para que o autoloading funcione corretamente, os caminhos dos arquivos devem corresponder à hierarquia completa de módulos/classes de acordo com as regras definidas pelo Zeitwerk.
3. Definindo rotas no engine do plugin
Crie um arquivo {plugin}/config/routes.rb
MyPluginModule::Engine.routes.draw do
get "/examples" => "examples#index"
# defina rotas aqui
end
Discourse::Application.routes.draw do
mount ::MyPluginModule::Engine, at: "my-plugin"
end
Este arquivo será carregado automaticamente pelo engine, e as alterações terão efeito sem reinicialização do servidor. Neste caso, a ação do controller estaria disponível em /my-plugin/examples.json.
4. Adicionando mais caminhos carregados automaticamente
Às vezes, você pode gostar de introduzir diretórios adicionais de arquivos Ruby carregáveis automaticamente. O exemplo mais comum é o diretório lib/ em um plugin.
Modifique a definição do seu engine para anexar lib/ aos caminhos de autoload do engine:
class Engine < ::Rails::Engine
engine_name PLUGIN_NAME
isolate_namespace MyPluginModule
config.autoload_paths << File.join(config.root, "lib")
end
Agora você pode definir um módulo lib como
{plugin}/lib/my_plugin_module/some_lib_module.rb
module ::MyPluginModule::SomeLibModule
end
E agora quaisquer referências a ::MyPluginModule::SomeLibModule carregarão automaticamente o módulo deste arquivo.
5. Lucro!
Todos esses arquivos agora serão carregados automaticamente sem chamadas require deliberadas. As alterações serão capturadas automaticamente pelo rails e recarregadas no local sem reinicialização do servidor.
Este documento é controlado por versão - sugira alterações no github.