[英]How can I automatically reload gem code on each request in development mode in Rails?
I am developing a Rails app where most of the code not specific to the app has been written inside of various gems, including some Rails engines and some 3rd party gems for which I am enhancing or fixing bugs.我正在开发一个 Rails 应用程序,其中大部分不是特定于该应用程序的代码都编写在各种 gem 中,包括一些 Rails 引擎和一些我正在增强或修复错误的第 3 方 gem。
gem 'mygem', path: File.expath_path('../../mygem', __FILE__)
Since a lot of the code in these gems is really part of the app, it's still changing frequently.由于这些 gem 中的许多代码实际上是应用程序的一部分,因此它仍然经常更改。 I'd like to be able to utilize the Rails feature where code is reloaded on each request when in development (ie when
config.cache_classes
is false), but this is only done within the normal application structure by default.我希望能够利用 Rails 功能,其中在开发时(即当
config.cache_classes
为 false 时)在每个请求上重新加载代码,但默认情况下这仅在正常的应用程序结构中完成。
How can I configure Rails to reload gem code on each request, just like with the app code?如何配置 Rails 以在每个请求上重新加载 gem 代码,就像使用应用程序代码一样?
I have found through trial and error that several steps are required, with the help of ActiveSupport
.在
ActiveSupport
的帮助下,我通过反复试验发现需要几个步骤。
Add activesupport
as a dependency in the .gemspec
files在
.gemspec
文件中添加activesupport
作为依赖.gemspec
spec.add_dependency 'activesupport'
Include ActiveSupport::Dependencies in the top-level module of your gem (this was the most elusive requirement)在您的 gem 的顶级模块中包含 ActiveSupport::Dependencies(这是最难以捉摸的要求)
require 'bundler'; Bundler.setup require 'active_support/dependencies' module MyGem unloadable include ActiveSupport::Dependencies end require 'my_gem/version.rb' # etc...
Set up your gem to use autoloading.设置您的 gem 以使用自动加载。 You an either manually use ruby autoload declarations to map symbols into filenames, or use the Rails-style folder-structure-to-module-hierarchy rules (see ActiveSupport #constantize )
您可以手动使用 ruby自动加载声明将符号映射到文件名,或者使用 Rails 样式的文件夹结构到模块层次结构规则(请参阅ActiveSupport #constantize )
In each module and class in your gem, add unloadable
.在 gem 的每个模块和类中,添加
unloadable
。
module MyModule unloadable end
In each file that depends on a module or class from the gem, including in the gem itself, declare them at the top of each file using require_dependency
.在依赖于 gem 中的模块或类的每个文件中,包括在 gem 本身中,使用
require_dependency
在每个文件的顶部声明它们。 Look up the path of the gem as necessary to properly resolve the paths.根据需要查找 gem 的路径以正确解析路径。
require_dependency "#{Gem.loaded_specs['my_gem'].full_gem_path}/lib/my_gem/myclass"
If you get exceptions after modifying a file and making a request, check that you haven't missed a dependency.如果在修改文件并发出请求后出现异常,请检查您是否没有遗漏依赖项。
For some interesting details see this comprehensive post on Rails (and ruby) autoloading.对于一些有趣的细节看这个on Rails的(和Ruby)自动加载综合后。
The solution that I used for Rails 6, with a dedicated Zeitwerk class loader and file checker :我用于 Rails 6 的解决方案,带有专用的 Zeitwerk 类加载器和文件检查器:
Add the gem to the Rails project using the path:
option in Gemfile
使用
Gemfile
的path:
选项将 gem 添加到 Rails 项目
gem 'mygem', path: 'TODO' # The root directory of the local gem
In the development.rb
, setup the classloader and the file watcher在
development.rb
,设置类加载器和文件观察器
gem_path = 'TODO' # The root directory of the local gem, the same used in Gemfile # Create a Zeitwerk class loader for each gem gem_lib_path = gem_path.join('lib').join(gem_path.basename) gem_loader = Zeitwerk::Registry.loader_for_gem(gem_lib_path) gem_loader.enable_reloading gem_loader.setup # Create a file watcher that will reload the gem classes when a file changes file_watcher = ActiveSupport::FileUpdateChecker.new(gem_path.glob('**/*')) do gem_loader.reload end # Plug it to Rails to be executed on each request Rails.application.reloaders << Class.new do def initialize(file_watcher) @file_watcher = file_watcher end def updated? @file_watcher.execute_if_updated end end.new(file_watcher)
With this, on each request, the class loader will reload the gem classes if one of them has been modified.有了这个,对于每个请求,如果其中一个被修改,类加载器将重新加载 gem 类。
For a detailed walthrough, see Embed a gem in a Rails project and enable autoreload .有关详细的遍历,请参阅在 Rails 项目中嵌入 gem 并启用 autoreload 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.