Muitos plugins incluem muitas definições de classes dentro de plugin.rb, ou usam require_relative para carregar arquivos ruby. Isso funciona, mas traz algumas desvantagens:
- Nenhuma recarga automática de alterações em desenvolvimento. Quaisquer alterações exigem uma reinicialização completa do servidor
- Colocar as chamadas
requirena ordem correta pode ser complicado - Se eles forem
require’ados fora do blocoafter_initialize, outras classes/módulos com autoload podem não estar disponíveis
Existe uma solução! Os plugins podem se apoiar no 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. Definir um módulo e um Rails::Engine para o seu plugin
Em plugin.rb, defina um módulo para o seu plugin com um PLUGIN_NAME exclusivo e adicione uma linha require_relative para carregar o arquivo do engine que estamos prestes a 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 serem observadas:
-
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 isso diretamente no arquivoplugin.rbnão funcionará. (O 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 (
documentação do rails) -
isolate_namespaceajuda a evitar que coisas vazem entre o core e o plugin (
documentação do Rails)
2. Definir arquivos ruby na estrutura de diretórios correta
O engine agora fará autoload de 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 terá autoload sempre que algo no Rails tentar acessar ::MyPluginModule::MyController. Para testar as coisas, tente acessar essa classe a partir do console rails.
Para que o autoloading funcione corretamente, os caminhos dos arquivos devem corresponder à hierarquia completa do módulo/classe 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 a necessidade de reiniciar o servidor. Neste caso, a ação do controller estaria disponível em /my-plugin/examples.json.
4. Adicionando mais caminhos com autoload
Às vezes, você pode querer introduzir diretórios adicionais de arquivos Ruby com autoload. O exemplo mais comum é o diretório lib/ em um plugin.
Modifique sua definição de 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 qualquer referência a ::MyPluginModule::SomeLibModule carregará automaticamente o módulo deste arquivo.
5. Lucro!
Todos esses arquivos agora serão carregados automaticamente sem quaisquer chamadas require deliberadas. As alterações serão capturadas automaticamente pelo rails e recarregadas no local sem a necessidade de reiniciar o servidor.
Este documento é controlado por versão - sugira alterações no github.