Muchos plugins incluyen muchas definiciones de clases dentro de plugin.rb, o usan require_relative para cargar archivos ruby. Eso funciona, pero tiene algunas desventajas:
- No se recargan automáticamente los cambios en desarrollo. Cualquier cambio requiere un reinicio completo del servidor.
- Conseguir las llamadas
requireen el orden correcto puede ser doloroso. - Si se cargan con
requirefuera del bloqueafter_initialize, es posible que otras clases/módulos cargados automáticamente no estén disponibles.
¡Hay una solución! Los plugins pueden apoyarse en el sistema de carga automática estándar de Rails. Para plugins nuevos, todo lo que necesitas está definido en el esqueleto del plugin. Este tema describe cómo adaptar un plugin existente y extender la configuración.
1. Define un módulo y un Rails::Engine para tu plugin
En plugin.rb, define un módulo para tu plugin con un PLUGIN_NAME único y añade una línea require_relative para cargar el archivo del motor que vamos a crear.
# nombre: mi-nombre-de-plugin
# ...
module ::MiModuloDelPlugin
PLUGIN_NAME = "mi-nombre-de-plugin"
end
require_relative "lib/mi_modulo_del_plugin/engine"
Ahora crea {plugin}/lib/mi_modulo_del_plugin/engine.rb:
module ::MiModuloDelPlugin
class Engine < ::Rails::Engine
engine_name PLUGIN_NAME
isolate_namespace MyPluginModule
end
end
Cosas importantes a tener en cuenta:
-
En
plugin.rb, debes incluir::antes del nombre de tu módulo para definirlo en el espacio de nombres raíz (de lo contrario, se definiría bajoPlugin::Instance). -
require_relative "lib/.../engine"debe estar en la raíz del archivoplugin.rb, no dentro de un bloqueafter_initialize. -
Poner el motor en su propio archivo bajo
lib/es importante. Definirlo directamente en el archivoplugin.rbno funcionará. (Rails usa la presencia de un directoriolib/para determinar la raíz del motor). -
La ruta del archivo debe incluir el nombre del módulo, según las reglas de Zeitwerk.
-
engine_namese usa como prefijo para las tareas de rake y cualquier ruta definida por el motor (
documentación de rails). -
isolate_namespaceayuda a evitar que las cosas se filtren entre el núcleo y el plugin (
documentación de Rails).
2. Define archivos ruby en la estructura de directorios correcta
El motor ahora cargará automáticamente todos los archivos en {plugin}/app/{type}/*. Por ejemplo, podemos definir un controlador.
{plugin}/app/controllers/mi_modulo_del_plugin/examples_controller.rb
module ::MiModuloDelPlugin
class ExamplesController < ::ApplicationController
requires_plugin PLUGIN_NAME
def index
render json: { hello: "world" }
end
end
end
Esto ahora se cargará automáticamente cada vez que algo en Rails intente acceder a ::MyPluginModule::MyController. Para probar, intenta acceder a esa clase desde la consola de rails.
Para que la carga automática funcione correctamente, las rutas de los archivos deben coincidir con la jerarquía completa de módulos/clases según las reglas definidas por Zeitwerk.
3. Define rutas en el motor del plugin
Crea un archivo {plugin}/config/routes.rb
MyPluginModule::Engine.routes.draw do
get "/examples" => "examples#index"
# define routes here
end
Discourse::Application.routes.draw do
mount ::MyPluginModule::Engine, at: "my-plugin"
end
Este archivo se cargará automáticamente por el motor, y los cambios surtirán efecto sin reiniciar el servidor. En este caso, la acción del controlador estaría disponible en /my-plugin/examples.json.
4. Añadir más rutas de carga automática
A veces, te puede gustar introducir directorios adicionales de archivos Ruby cargables automáticamente. El ejemplo más común es el directorio lib/ en un plugin.
Modifica la definición de tu motor para añadir lib/ a las rutas de carga automática del motor:
class Engine < ::Rails::Engine
engine_name PLUGIN_NAME
isolate_namespace MyPluginModule
config.autoload_paths << File.join(config.root, "lib")
end
Ahora puedes definir un módulo lib como
{plugin}/lib/mi_modulo_del_plugin/some_lib_module.rb
module ::MiModuloDelPlugin::SomeLibModule
end
Y ahora cualquier referencia a ::MyPluginModule::SomeLibModule cargará automáticamente el módulo desde este archivo.
5. ¡Beneficio!
Todos estos archivos ahora se cargarán automáticamente sin llamadas require deliberadas. Rails detectará automáticamente los cambios y los recargará en su lugar sin necesidad de reiniciar el servidor.
Este documento está controlado por versiones - sugiere cambios en github.