首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Zeitwerk:将引擎/宝石目录添加到父Rails应用程序的自动路径中

Zeitwerk:将引擎/宝石目录添加到父Rails应用程序的自动路径中
EN

Stack Overflow用户
提问于 2022-07-06 17:44:53
回答 1查看 515关注 0票数 1

我正在尝试切换到现有的、较老的Gem (Rails::Engine)中的Zeitwerk。到目前为止,所有文件都是手动的required和autoloaded。加上引擎的lib文件夹是通过autoload_paths中的config.autoload_paths += paths["lib"].to_a添加到class MyEngine < Rails::Engine中的。

通过在自述上描述的方式,使用Zeitwerk的开关工作得很好

代码语言:javascript
复制
require "zeitwerk"
loader = Zeitwerk::Loader.for_gem
.
. --> more project specific stuff here
.
loader.setup # ready!

到目前一切尚好!现在,我想在Rails应用程序中使用Gem,并将引擎的目录添加到Rails应用程序的autoload_path中。这在前面提到的config.autoload_paths中运行得很好。如果我现在就这样做,它就会失败,出现以下错误消息:

代码语言:javascript
复制
Zeitwerk::Error:
  loader

#<Zeitwerk::Loader:0x00000001094d4bd0
...

wants to manage directory /gems/<NameOfGem>/lib, which is already managed by

#<Zeitwerk::Loader:0x0000000106b2d728
...

将引擎的库目录添加到Rails应用程序的自动路径的正确方法是什么?

谢谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-07-06 21:47:48

Rails设置两个加载程序mainonce

代码语言:javascript
复制
Rails.autoloaders.main
Rails.autoloaders.once

这些只是Zeitwerk::Loader的实例。Rails还为您提供了一个配置,以便将根目录添加到这些加载程序中:

代码语言:javascript
复制
config.autoload_paths         # main
config.autoload_once_paths    # once

当gem的lib目录通过这些信任之一添加到autoload中时,lib成为一个根目录:

代码语言:javascript
复制
# config.autoload_paths += paths["lib"].to_a

>> Rails.autoloaders.main.root_dirs
=> 
...                    
 "/home/alex/code/stackoverflow/my_engine/lib"=>Object,
...

当调用gem中的类时,zeitwerk使用注册加载程序来查找和加载与该类相对应的文件。

如果创业板然后设置了自己的加载程序:

代码语言:javascript
复制
require "zeitwerk"
loader = Zeitwerk::Loader.for_gem
loader.setup

Zeitwerk::Loader的另一个实例是用自己的根目录创建的:

代码语言:javascript
复制
>> Zeitwerk::Registry.loaders.detect { |z| z.tag == "my_engine" }
=> 
#<Zeitwerk::GemLoader:0x00007fe5e53e0f80
...
 @root_dirs={"/home/alex/code/stackoverflow/my_engine/lib"=>Object},
...

# NOTE: these are the two loaders registered by rails
>> Zeitwerk::Registry.loaders.select { |z| z.tag =~ /rails/ }.count
=> 2

Zeitwerk不允许两个加载程序有一个共享目录,并引发一个错误,显示两个冲突的加载程序。

因为gem是Rails::Engine,所以最好的选择是让rails管理zeitwerk加载器并删除Zeitwerk::Loader.for_gem设置。

代码语言:javascript
复制
# only use rails config
config.autoload_paths += paths["lib"].to_a

另一方面,gem加载器已经被设置,并且不需要config.autoload_paths。

代码语言:javascript
复制
# NOTE: without any loaders
>> MyEngine::Test
# (irb):1:in `<main>': uninitialized constant MyEngine::Test (NameError)                                            
# MyEngine::Test                                
#         ^^^^^^

# NOTE: with gem loader
#
#   require "zeitwerk"
#   loader = Zeitwerk::Loader.for_gem
#   loader.setup                           
#
>> MyEngine::Test
=> MyEngine::Test

# NOTE: with rails `main` loader
#
#   config.autoload_paths += paths["lib"].to_a
#
>> MyEngine::Test
=> MyEngine::Test

# NOTE: with gem loader and rails loader
$ bin/rails c
# /home/alex/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/zeitwerk-2.6.0/lib/zeitwerk/loader.rb:480:in
# `block (3 levels) in raise_if_conflicting_directory':
# loader (Zeitwerk::Error)

更新

代码语言:javascript
复制
# Use rails loaders
# config.autoload_path          .->  Zeitwerk::Loader(@tag=rails.main)
# config.autoload_once_path     |->  Zeitwerk::Loader(@tag=rails.once)
#                               |
# Or create a new loader        |
# Zeitwerk::Loader.for_gem      |->  Zeitwerk::GemLoader(@tag=my_engine)
#                               |
# my_engine/lib can only be in one of these

齐特沃克负责装货和重装。Rails只是这里的另一块宝石。

如果不使用rails配置,Zeitwerk将通过Zeitwerk::GemLoader(@tag=my_engine)找到gem创建的文件。

如果使用rails配置,Zeitwerk将通过Zeitwerk::Loader(@tag=rails.main)找到rails创建的文件(使GemLoader变得不必要)。

如果lib是现有加载程序中的根目录,则不需要对lib目录中的文件有任何要求或自动加载。除了在Zeitwerk启动之前需要的东西,比如MyEngine::Engine来自lib/my_engine/engine.rb。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72887860

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档