Вопрос о плагинах Discourse и config/initializers в Rails 6

Привет, гуру плагинов Discourse!

Вопрос по поводу плагинов Discourse и инициализаторов Rails.

Если плагин Discourse содержит директорию “config” и поддиректорию “initializers” внутри “config”, читает ли приложение Discourse на базе Rails все файлы инициализаторов плагинов из директории “initializers”, как это делает Rails 6?

Причина моего вопроса: я сейчас пишу с нуля приложение “бэк-офис” на Rails 6 (только Rails, без EmberJS или других JS-фреймворков) для клиента, и у меня есть следующая структура поддиректорий внутри initializers:

./config/initializers/client/

… и все уникальные для клиента инициализаторы находятся в поддиректории “client”.

Rails 6 читает все файлы из стандартной директории инициализаторов (включая поддиректории), поэтому я задумался: будут ли плагины Discourse с аналогичной структурой директорий для инициализаторов вести себя как Rails 6 и читать все инициализаторы плагина, например так:

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

… без регистрации этих ассетов в файле plugin.rb?

Спасибо!

PS: Я просмотрел около 10 плагинов Discourse на GitHub, и ни в одном из них не оказалось инициализаторов внутри директории config. Именно поэтому я решил задать этот вопрос (к тому же моя среда разработки Rails сейчас настроена не для Discourse, а для проекта клиента).

Я также хочу узнать, чем плагин Discourse отличается от обычного Rails Engine. Я просто смотрел в исходный код, но не понял многого.

После беглого просмотра Ruby on Rails Guides: Configuring Rails Applications
мне кажется, что plugin.rb во многом то же самое. Большинство достаточно крупных плагинов используют его как точку входа к логике, а не как саму логику.

Да, я в последнее время часто читаю это руководство по Rails. В целом, я «в порядке» с тем, как работает конфигурация в Rails 6 (все еще учусь, но с каждым днем чувствую себя увереннее).

Меня просто интересует, можно ли использовать ту же структуру в плагине для Discourse (для инициализаторов), будет ли Rails читать инициализаторы в подкаталогах так же, как в Rails 6, или нам нужно зарегистрировать каталог инициализаторов плагина как конфигурационный «ресурс» (насколько я знаю, лучшего слова нет) в файле plugin.rb.

Вчера я изучал информацию о плагинах Rails и немного сравнивал их.

Насколько я знаю, Discourse не читает никакие ruby-файлы, кроме plugin.rb. Он читает js-файлы и файлы конфигурации. Все ruby-файлы должны быть подключены через require в plugin.rb.

Я тоже так считаю.

Вы загружаете любые дополнительные файлы Ruby, которые вам нужны, изнутри plugin.rb.

Вот пример из плагина Follow:

У меня сложилось примерно такое же впечатление, когда я изучал множество плагинов Discourse на GitHub.

Кажется, Discourse читает только plugin.rb, и мы должны загружать все остальные ruby-файлы, которые могут понадобиться, например инициализаторы, прямо в plugin.rb.

Однако я надеялся, что ошибаюсь, и что интеграция плагинов Discourse с Rails может быть «глубже», так как я очень привык к тому, насколько прекрасен Rails 6.

Спасибо и вам за подтверждение.

Думаю, в файле plugin.rb должен быть способ подключения кода инициализации.
Вы пробовали это в plugin.rb?

Rails.application.config.before_initialize do
  # код инициализации здесь
end

Да, это не проблема — вызывать и загружать инициализаторы в plugin.rb.

Причина моего вопроса в том, что я сейчас пишу довольно большое приложение на Rails 6 для бизнеса, конвертируя их устаревшие скрипты для внутреннего использования (разработанные за несколько десятилетий) в приложение на Rails. Чтобы добавить инициализаторы, я просто создаю подкаталог в config/initializers (в Rails), и все мои файлы инициализаторов подключаются автоматически, без необходимости писать код для их включения в Rails.

Спасибо всем за ответы. Очень признателен!

Да, мне бы очень хотелось, чтобы преимущества Rails были перенесены в плагины Discourse. Одним из моих личных фаворитов была бы возможность live-перезагрузки Ruby-файлов без перезапуска сервера.

Для этого и предназначен reloadable_patch. Если вы обернете изменения Ruby-классов в reloadable_patch, они должны перезагружаться в реальном времени!

Могу ли я для разработки обернуть в это весь файл plugin.rb? Если серьёзно, насколько далеко мы можем с этим зайти?

Также, верно, что добавление новых файлов или изменение любых yml-файлов требует перезапуска сервера?

Вам не следует делать reloadable_patch для всего. Многие методы, определённые в instance.rb для упрощения разработки плагинов, используют reloadable_patch internally, например add_to_serializer.

В идеале наш API плагинов должен быть достаточно хорошим, чтобы вам не приходилось делать огромное количество reloadable_patch.

Да, это верно. Интересно, можно ли что-то сделать с изменениями в yml-файлах; это лично меня раздражает.

Абсолютно верно. Я не знал, что reloadable_patch предназначен для поддержки горячей перезагрузки. Я могу придумать множество сценариев использования, помимо тех, где Discourse уже применяет это. Например:

reloadable_patch do
 require 'x/y/z'
end

или патчи-обезьяны.

Я считаю, что удаление или добавление такой функции всё равно создаст проблему, поскольку reloadable_patch вызывается внутри этой функции.

В любом случае, это очень помогает.

Я начал изучать возможность перезагрузки изменений в YAML-файлах в реальном времени, и это действительно работает. Плагины могут нарушить эту функцию, если они не используют корректно reloadable_patch, но как только все ваши плагины смогут безопасно перезагружаться, ваши изменения в YAML-файлах тоже будут работать.

Однако было бы очень полезно, если бы вы могли описать точные шаги для использования reloadable patch.

Вот что я попробовал, но без особого успеха (я наверняка что-то упускаю):

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

Как только сервер запускается, и я меняю nocheck на check, он всё ещё выводит nocheck после перезагрузки маршрута темы.

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

По-прежнему безрезультатно, когда я перезагружаю любую страницу после изменения строки внутри puts.

Кажется, я ввёл вас в заблуждение в предыдущих сообщениях. reloadable_patch полезен для разработки в Discourse, но @david очень хорошо объяснил его использование:


Всё, что находится внутри блока after_initialize в файле plugin.rb, загружается только при запуске приложения, а не при последующих перезагрузках.

Итак, предположим, вы хотите добавить что-то в сериализатор пользователя. В обычном случае поведение будет следующим:

При запуске:

  • Discourse загружает user_serializer.rb
  • Discourse загружает plugin.rb, который содержит переопределение для user_serializer

При перезагрузке:

  • Discourse перезагружает user_serializer.rb
  • (патч из plugin.rb не перезагружается, переопределение плагина теряется)

С нашей системой reloadable_patch:

При запуске:

  • Discourse загружает user_serializer.rb
  • Discourse загружает plugin.rb и регистрирует reloadable_patch для user_serializer
  • Выполняются reloadable патчи

При перезагрузке:

  • Discourse перезагружает user_serializer.rb
  • Выполняются reloadable патчи
  • (ура, переопределение плагина продолжает работать)

Это описывает фундаментальное свойство Rails, которое не имеет прямого отношения к Discourse.

В Rails все инициализаторы загружаются только при запуске Rails. Следовательно, любой плагин, выполняющий код на основе инициализатора (например, «after_initializer»), будет выполняться только при запуске или перезапуске Rails (поправьте меня, если я ошибаюсь).

Причина, по которой я знаком с этим, заключается в том, что я в настоящее время разрабатываю приложение на Rails для клиента и написал множество инициализаторов для различных задач (булевы значения, статические массивы и т. д.). В каждом случае, если мы меняем код в инициализаторе Rails, необходимо перезапустить Rails («Ctrl+C, rails s в режиме разработки»), чтобы новые значения из инициализаторов применились в приложении Rails.

Поправьте меня, если я не прав! Спасибо.

Иногда мне кажется, что это может сбить с толку некоторых разработчиков плагинов Discourse, особенно тех, кто работает преимущественно с плагинами Discourse, а не с приложениями Rails в целом, когда мы пишем «Discourse делает это» или «Discourse делает то», хотя на самом деле мы описываем базовую функцию или свойство Rails, не обязательно относящееся к Discourse как таковому.

Rails 6 считывает все файлы в директории config/initializers (и во всех поддиректориях config/initializers) только при запуске Rails. Аналогично (не уверен на 100% насчет плагинов), плагин Discourse, код которого зависит от after_initialize, будет (пожалуйста, подтвердите это кто-нибудь!) загружаться приложением Rails только при запуске или перезапуске Rails, поскольку это фундаментальное свойство процесса загрузки Rails.

Мне кажется, что все здесь работающие с Rails уже знают это. Я только начинаю узнавать эти детали (и чувствую, что мне еще далеко до эксперта), потому что в последнее время я каждый день работаю над приложением на Rails. Кстати, теперь я жалею, что не начал работать с Rails десять лет назад, так как, имея опыт разработки в стеке LAMP, я нахожу Rails гораздо более удобным (легким и приятным в работе).

В этом году я стал большим поклонником Rails и очень благодарен Discourse за то, что он открыл мне этот путь.

Еще раз, поправьте меня, если я не прав! Спасибо. Я стараюсь стать более экспертом в Rails.

Да! Это верно, как и ваше понимание инициализаторов Rails.

Я тоже большой поклонник Rails :slight_smile: