Plugins de Discourse y pregunta de configuración de Rails 6 config/initializers

Hola, expertos en plugins de Discourse,

Solo una pregunta rápida sobre los plugins de Discourse y los inicializadores de Rails.

Si un plugin de Discourse tiene un directorio llamado “config” y un subdirectorio bajo “config” llamado “initializers”, ¿lee la aplicación Rails de Discourse todos los archivos de inicializador del plugin bajo el directorio “initializers” como lo hace Rails 6?

La razón de mi pregunta es que estoy en medio de escribir una aplicación “back office” de Rails 6 (solo Rails, sin EmberJS ni otro framework JS encima) desde cero para un cliente, y tengo un directorio bajo initializers así:

./config/initializers/client/

… y todos los inicializadores únicos del cliente están en el subdirectorio “client”.

Rails 6 lee todos los archivos bajo el directorio de inicializadores estándar (incluso subdirectorios); por lo que me preguntaba si los plugins de Discourse, con una estructura de directorios similar para inicializadores, se comportarán como Rails 6 y leerán todos los inicializadores en el plugin de manera como esta:

./plugins/my_plugin/config/initializers/myclient/
      client_initializer1.rb
      client_initializer2.rb
      client_initializer2.rb

… sin registrar estos activos en el archivo plugin.rb?

¡Gracias!

PD: Revisé alrededor de 10 plugins de Discourse en GitHub y ninguno de los que vi tenía inicializadores bajo el directorio config. Por eso decidí publicar la pregunta (y mi entorno de desarrollo de Rails no está configurado para Discourse en este momento, todo está configurado para el cliente).

También quiero saber en qué se diferencia un plugin de Discourse de un motor de Rails común. Estuve revisando el código fuente, pero no entendí mucho.

Después de echar un vistazo a esto Ruby on Rails Guides: Configuring Rails Applications
creo que plugin.rb es prácticamente lo mismo. La mayoría de los plugins de tamaño considerable lo utilizan como punto de entrada a la lógica en lugar de contener la lógica en sí.

Sí, he leído esa guía de Rails bastante últimamente. Básicamente, estoy “bien” con cómo funciona la configuración de Rails 6 (aún estoy aprendiendo, pero me siento cada vez más cómodo día a día).

Solo me pregunto si podemos usar la misma estructura en un plugin de Discourse (para los inicializadores), si Rails leerá los inicializadores en los subdirectorios como lo hace en Rails 6; o si tenemos que registrar el directorio de inicializadores del plugin como un “activo” de configuración (por falta de una palabra mejor) en plugin.rb.

Estaba investigando sobre los plugins de Rails ayer y comparando un poco también.

Hasta donde sé, Discourse no lee ningún archivo Ruby aparte de plugin.rb. Sí lee los archivos js y de configuración. Todos los archivos Ruby deben ser requiredos en plugin.rb.

Yo también lo creo.

Cargas cualquier archivo Ruby adicional que necesites desde dentro de plugin.rb.

Aquí tienes un ejemplo del plugin Follow:

Esa es más o menos mi impresión tras leer varios plugins de Discourse en GitHub.

Parece que Discourse solo lee plugin.rb y tenemos que cargar todos los demás archivos Ruby que necesitemos, como los inicializadores, dentro de plugin.rb.

Sin embargo, esperaba estar equivocado y que hubiera una integración más “profunda” entre los plugins de Discourse y Rails; ya que me he acostumbrado mucho a lo genial que es Rails 6.

Gracias por confirmar también.

Creo que debería haber una forma de incluir código de inicialización también en plugin.rb.
¿Lo has probado en plugin.rb?

Rails.application.config.before_initialize do
  # el código de inicialización va aquí
end

Sí, no hay problema al llamar y cargar los inicializadores en plugin.rb.

La razón de mi pregunta es que actualmente estoy escribiendo una aplicación Rails 6 bastante grande para una empresa, convirtiendo sus scripts heredados de oficina (de varias décadas) en una aplicación Rails. Para agregar inicializadores, simplemente tengo un subdirectorio bajo config/initializers (en Rails) y todos mis archivos de inicialización se incluyen tan bien sin necesidad de escribir ningún código para incluir estos archivos en Rails.

Gracias por todas sus respuestas. ¡Muy apreciadas!

Sí, me encantaría que esas ventajas de Rails se portaran a los complementos de Discourse. Una de mis favoritas personales sería poder recargar en vivo los archivos de Ruby sin tener que reiniciar el servidor.

Para eso sirve reloadable_patch. Si envuelves los cambios en las clases de Ruby con reloadable_patch, ¡deberían recargarse en vivo!

¿Puedo envolver todo el archivo plugin.rb en él para desarrollo? Más seriamente, ¿hasta dónde podemos llegar con esto?

Además, ¿agregar nuevos archivos o cambiar cualquier archivo YAML requiere reiniciar el servidor, verdad?

No deberías tener que hacer un reloadable_patch para todo. Muchos de los métodos definidos en instance.rb para facilitar el desarrollo de plugins utilizan internamente reloadable_patch, como add_to_serializer.

Idealmente, nuestra API de plugins es lo suficientemente buena como para que no tengas que hacer una cantidad absurda de reloadable_patch.

Sí, eso es cierto. Me pregunto si se puede hacer algo al respecto con los cambios en los archivos yml; eso personalmente me molesta.

Es cierto. No sabía que reloadable_patch estaba pensado para soportar la recarga en vivo. Se me ocurren muchos casos de uso distintos a los que Discourse ya utiliza. Es decir,

reloadable_patch do
 require 'x/y/z'
end

o parches de tipo monkey patch.

Creo que eliminar o agregar una función así seguiría siendo un problema, ya que reloadable_patch se llama dentro de la función.

En cualquier caso, ayuda mucho.

Empecé a investigar los cambios en archivos YML con recarga en vivo y, de hecho, funciona. Los plugins pueden interrumpir esta recarga en vivo si no utilizan correctamente reloadable_patch, pero una vez que todos tus plugins puedan recargarse de forma segura, tus cambios en YML también lo harán.

Sería de gran ayuda si pudieras describir los pasos exactos para usar el parche recargable.

Esto es lo que intenté, sin mucho éxito (seguro me estoy perdiendo algo):

after_initialize do
    add_to_serializer(:topic_view, :check, false) do
        puts 'nocheck'
    end
end

Una vez que el servidor se inicia y cambio nocheck por check, sigue imprimiendo nocheck después de recargar la ruta del tema.

after_initialize do
    reloadable_patch do |plugin|
        puts 'nocheck'
    end
end

Sigo sin tener éxito al recargar cualquier página después de cambiar la cadena dentro de puts.

Supongo que te he confundido en los mensajes anteriores. reloadable_patch es útil para el desarrollo de Discourse, pero @david explicó muy bien su uso:


Cualquier cosa dentro del bloque after_initialize de plugin.rb solo se carga durante el inicio de la aplicación, y no en las recargas posteriores.

Por lo tanto, supongamos que quieres agregar algo al serializador de usuario. El comportamiento normal sería así:

Al iniciar:

  • Discourse carga user_serializer.rb
  • Discourse carga plugin.rb, que tiene una sobrescritura para user_serializer

Al recargar:

  • Discourse vuelve a cargar user_serializer.rb
  • (el parche de plugin.rb no se vuelve a cargar, se pierde la sobrescritura del plugin)

Con nuestro sistema reloadable_patch:

Al iniciar:

  • Discourse carga user_serializer.rb
  • Discourse carga plugin.rb y registra el reloadable_patch para el serializador de usuario
  • Se ejecutan los parches recargables

Al recargar:

  • Discourse vuelve a cargar user_serializer.rb
  • Se ejecutan los parches recargables
  • (¡genial, la sobrescritura del plugin sigue funcionando!)

Esto describe una propiedad fundamental de Rails, que no es específica de Discourse.

En Rails, todos los inicializadores se cargan únicamente cuando Rails se inicia, por lo que cualquier plugin que ejecute código basado en un inicializador, como “after_initializer”, solo se ejecutará al iniciar o reiniciar Rails (por favor, corríjanme si estoy equivocado).

La razón por la que estoy familiarizado con esto es que actualmente estoy construyendo una aplicación Rails para un cliente y he escrito muchos inicializadores para diversas tareas (valores booleanos, arreglos estáticos, etc.). En cada caso, si cambiamos cualquier código en un inicializador de Rails, es necesario reiniciar Rails (“Control c, rails s en dev”) para que los nuevos valores de los inicializadores se reflejen en la aplicación Rails.

¡Por favor, corríjanme si estoy equivocado! Gracias.

A veces, creo que podría resultar un poco confuso para algunos desarrolladores de plugins de Discourse, especialmente aquellos que trabajan principalmente en plugins de Discourse y no en aplicaciones Rails en general, cuando escribimos “Discourse hace esto” o “Discourse hace aquello”, cuando en realidad estamos describiendo una función o propiedad fundamental de Rails que no es necesariamente específica de Discourse, en sí misma.

Rails 6 lee todos los archivos del directorio config/initializers (y todos los subdirectorios de config/initializers) únicamente cuando Rails se inicia. De manera similar (no estoy 100% seguro con los plugins), un plugin de Discourse con código dependiente de after_initialize será (por favor, confírmelo cualquiera) cargado por la aplicación Rails solo cuando Rails se inicia o reinicia, porque esta es una propiedad fundamental del proceso de arranque de Rails.

Supongo que todos aquí que trabajan con Rails ya lo saben. Solo yo estoy empezando a conocer estos detalles (y siento que tengo un largo camino por recorrer para ser un experto); porque actualmente estoy trabajando todos los días en una aplicación Rails (en estos días), la cual, por cierto, ahora desearía haber empezado a trabajar con Rails hace una década, ya que provengo de un entorno de desarrollo LAMP y encuentro que Rails es mucho mejor (fácil y divertido de trabajar).

Me he convertido en un gran fan de Rails este año y estoy muy agradecido con Discourse por haberme iniciado en ese camino.

De nuevo, ¡por favor, corríjanme si estoy equivocado! Gracias. Estoy tratando de ser más experto en Rails.

¡Sí! Esto es correcto, al igual que tu comprensión de los inicializadores de Rails.

También soy un gran fan de Rails :slight_smile: