Rails 6: автоматически перезагружать локальный гем при изменении

Я параллельно разрабатываю приложение Rails 6 и Gem.

Раньше я использовал require_reloader Gem, чтобы Rails перезагружал Gem при изменении любых файлов в локальном каталоге Gem.

Поскольку Zeitwerk стал новым загрузчиком в Rails 6, этот Gem, похоже, больше не работает.

Итак, мой вопрос: каков канонический способ разработки приложений Gem и Rails 6 параллельно, чтобы изменения, внесенные в файлы Gem, автоматически отображались в Rails?

1 ответ

Я также не нашел канонического решения этой проблемы, но в контексте Rails: Auto-reload gem-файлы, используемые в фиктивном приложении , нашел обходной путь:

Предположим, что папка gem

      ~/rails/foo_gem

и папка rails-6-app:

      ~/rails/bar_app

Чтобы перезагрузить код gem в приложении при изменении файловой системы, мне нужно было сделать три шага:

  1. Отмените регистрацию загрузчика zeitwerk, определенного в нем, который обрабатывает загрузку различных файлов драгоценных камней.
  2. Определите новый загрузчик zeitwerk в приложении, для которого настроено расширение .
  3. Настройте наблюдатель за файловой системой и инициируйте перезагрузку при изменении файла gem.

в

      # ~/rails/foo_gem/lib/foo_gem.rb

# require 'foo_gem/bar`  # Did not work. Instead:

# (a) use zeitwerk:
require "zeitwerk"
loader = Zeitwerk::Loader.new
loader.push_dir File.join(__dir__)
loader.tag = "foo_gem"
loader.setup

# or (b) use autoload:
module FooGem
  autoload :Bar, "foo_gem/bar"
end

Примечание:

  • В прошлом я просто загружал все рубиновые файлы драгоценного камня из своего рода индексного файла, который называется точно так же, как и драгоценный камень, здесь: . Здесь это не работает, потому что zeitwerk игнорирует файлы, которые ранее были загружены с помощью require. Вместо этого мне нужно было создать отдельный загрузчик zeitwerk для драгоценного камня.
  • У этого загрузчика нет, потому что в противном случае для этого драгоценного камня была бы включена перезагрузка при каждом использовании драгоценного камня, а не только во время разработки драгоценного камня.
  • Я дал загрузчику tag, что позволяет найти этот загрузчик позже в Zeitwerk::Registryдля того, чтобы снять его с регистрации.
  • Вместо использования zeitwerk в foo_gem.rb, можно также использовать там, как это делает гем devise . Это лучший способ, если вы хотите поддерживать более ранние версии rails, чем 6, потому что для zeitwerk требуется rails 6+. С использованием autoloadздесь также делает ненужным шаг 1 в следующем разделе.

Zeitwerk::Loaderв development.rbприложения

      # ~/rails/bar_app/config/environments/development.rb

# 1. Unregister the zeitwerk loader defined in foo_gem.rb that handles loading
#    the different gem files.
#
Zeitwerk::Registry.loaders.detect { |l| l.tag == "foo_gem" }.unregister

# 2. Define a new zeitwerk loader in the development.rb of the app
#    that is configured with enable_reloading.
#
gem_root_path = Pathname.new(Gem.loaded_specs["foo_gem"].full_gem_path)
gem_loader = Zeitwerk::Loader.new
gem_loader.push_dir gem_root_path.join("lib")
gem_loader.enable_reloading
gem_loader.setup

# 3. Setup a file-system watcher and trigger a reload when a gem file changes.
#
Listen.to gem_root_path.join("lib"), only: /\.rb$/ do
  gem_loader.reload
end.start

Примечание:

  • Zeitwerk не позволяет двум загрузчикам управлять одними и теми же файлами. Поэтому мне нужно отменить регистрацию ранее определенного загрузчика с тегом "foo_gem".
  • Новый загрузчик, используемый в приложении, имеет enable_reloading. Таким образом, при использовании приложения с , или при запуске спецификаций файлы гема могут быть перезагружены.
  • Файлы драгоценных камней не перезагружаются автоматически zeitwerk. Нужен наблюдатель за файловой системой, чтобы запускать перезагрузку при изменении файловой системы. мне не удалось получитьActiveSupport::FileUpdateCheckerработающий. Вместо этого я использовал гем listen в качестве наблюдателя за файловой системой.

С этой настройкой при использовании rails console, или спецификации bar_app, gem-файлов foo_gemперезагружаются после редактирования, что означает, что больше не нужно перезапускать rails serverчтобы забрать изменения.

Однако я не нахожу этот обходной путь очень удобным.

Другие вопросы по тегам