简体   繁体   English

如何在 Rails 的开发模式下为每个请求自动重新加载 gem 代码?

[英]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使用Gemfilepath:选项将 gem 添加到 Rails 项目

    gem 'mygem', path: 'TODO' # The root directory of the local gem
  • In the development.rb , setup the classloader and the file watcherdevelopment.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.

相关问题 如何在开发模式下强制Rails 3.2按请求重新加载已安装的机架应用程序? - How can I force Rails 3.2 to reload mounted rack app per request in development mode? 在开发模式下重新加载Rails 3初始化程序 - Reload Rails 3 initializer in development mode 如何在开发模式下控制Rails / Webrick调试日志记录? - How can I control rails/webrick debug logging in development mode? 如何为开发模式的链接配置Rails 3.0.7主机? - How can I configure Rails 3.0.7 host for links for development mode? 如何让Rails 3在开发模式下重新加载STI类? - How to make Rails 3 reload STI classes in development mode? 在开发人员模式下,如何明确告诉Rails在每个请求上重新加载文件? - How to tell Rails explicitly to reload a file on each request while in dev mode? 如何在Rails 2.3中强制重新加载所有供应商/插件(开发模式) - How to force reload all vendor/plugins in rails 2.3 (development mode) Rails 6:更改时自动重新加载本地 gem - Rails 6: Automatically reload local gem on change 如何强制我的插件重新加载每个请求? - How can I force my plugin to reload with each request? Rails 3路线-如何自动映射每个动作(例外)? - Rails 3 routes - how can I automatically map each action (with exceptions)?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM