ruby-on-rails - Rails 6:更改时自动重新加载本地 gem
问题描述
我正在并行开发 Rails 6 应用程序和 Gem。
过去,我使用了require_reloader Gem,这样当 Gem 的本地目录中的任何文件发生更改时,Rails 都会重新加载 Gem。
随着 Zeitwerk 成为 Rails 6 中的新加载程序,这个 Gem 似乎不再工作了。
所以我的问题是:并行开发 Gem 和 Rails 6 应用程序以便对 Gem 文件所做的更改在 Rails 中自动可见的规范方法是什么?
解决方案
我也没有找到解决这个问题的规范解决方案,但是,在Rails: Auto-reload gem files used in dummy app的上下文中,找到了一种解决方法:
假设 gem 文件夹是
~/rails/foo_gem
rails-6-app 文件夹是:
~/rails/bar_app
要在应用程序中重新加载文件系统更改的 gem 代码,我需要执行三个步骤:
foo_gem.rb
取消注册处理加载不同 gem 文件的 zeitwerk 加载程序。- 在
development.rb
配置了enable_reloading
. - 设置文件系统观察程序并在 gem 文件更改时触发重新加载。
Zeitwerk::Loader
在foo_gem.rb
# ~/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
笔记:
- 过去,我只是
require
从一种类似于 gem 的索引文件中加载 gem 的所有 ruby 文件,这里:foo_gem.rb
. 这在这里不起作用,因为 zeitwerk 似乎忽略了以前加载的文件require
。相反,我需要为 gem 创建一个单独的 zeitwerk 加载器。 - 这个加载器没有
enable_reloading
,因为否则,无论何时使用 gem,都会为这个 gem 启用重新加载,而不仅仅是在开发 gem 时。 - 我给了加载器 a
tag
,它允许稍后找到这个加载器Zeitwerk::Registry
以便取消注册它。 - 除了在 zeitwerk 中使用之外
foo_gem.rb
,还可以像 devise gem 那样autoload
使用那里。如果您想支持早于 6 的 rails 版本,这是最好的方法,因为 zeitwerk 需要 rails 6+。在此处使用也使下一节中的步骤 1 变得不必要。autoload
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 不允许两个加载程序管理相同的文件。因此,我需要注销之前定义的 loader 标记
"foo_gem"
。 - 应用程序中使用的新加载程序具有
enable_reloading
. 因此,当使用带有rails server
,的应用程序rails console
或运行规范时,可以重新加载 gem 文件。 - zeitwerk 不会自动重新加载 gem 文件。需要一个文件系统观察器来触发文件系统更改的重新加载。我没有设法得到
ActiveSupport::FileUpdateChecker
工作。相反,我使用了listen gem 作为文件系统观察器。
通过此设置,当使用bar_apprails server
的、 或 specs 时,编辑后的 gem 文件会重新加载,这意味着不再需要重新启动来获取更改。rails console
foo_gem
rails server
但是,我发现这种解决方法不是很方便。
推荐阅读
- machine-learning - 如何使用遗传算法在 WEKA 中找到投票分类器的权重?
- html - 我想要一个下拉菜单,但是当我将位置设置为“固定”时它不起作用
- c# - 如何解决 .NET Core 客户端应用程序中的 WS2007HttpBinding WCF 服务绑定
- javascript - Django 和 JavaScript 如何协同工作以运行 Python 脚本?
- java - 何时使用请求范围的 bean 与将参数向下传递堆栈?
- c# - 在 Foreach 循环中使用 While 时 UI 未加载
- oracle11g - Oracle 11G 安装程序在安装过程中消失
- c# - 使用 Firebase 实时数据库和统一检查值是否存在
- android - Activity 进入 onPause() 生命周期时不会立即调用 Activity 生命周期 onStop()
- rx-java2 - Observable.switchMap 不会中断 Observable