运行 'rspec' 时,Rails 7 引擎中的 'FrozenError: can't modify frozen Array'

`FrozenError: can't modify frozen Array` in Rails 7 Engine when running `rspec`

提问人:John 提问时间:8/26/2023 最后编辑:John 更新时间:8/29/2023 访问量:274

问:

我刚刚将引擎从 Rails 5 升级到 Rails 7。这个错误开始出现在 Rails 6.1.7.6 中,但我认为它可能已经在 Rails 7 中修复了。

这是我运行时遇到的错误rspec

An error occurred while loading ./spec/awesome_engine/services/awesome_engine/pdf_exporter/termination_spec.rb.
Failure/Error: Rails.application.initialize!

FrozenError:
  can't modify frozen Array: ["/Users/bobbert/.gem/ruby/2.7.6/gems/actiontext-7.0.7.2/app/helpers", "/Users/bobbert/.gem/ruby/2.7.6/gems/actiontext-7.0.7.2/app/models"]
# /Users/bobbert/.gem/ruby/2.7.6/gems/railties-7.0.7.2/lib/rails/engine.rb:575:in `unshift'
# /Users/bobbert/.gem/ruby/2.7.6/gems/railties-7.0.7.2/lib/rails/engine.rb:575:in `block in <class:Engine>'
# /Users/bobbert/.gem/ruby/2.7.6/gems/railties-7.0.7.2/lib/rails/initializable.rb:32:in `instance_exec'
# /Users/bobbert/.gem/ruby/2.7.6/gems/railties-7.0.7.2/lib/rails/initializable.rb:32:in `run'
# /Users/bobbert/.gem/ruby/2.7.6/gems/railties-7.0.7.2/lib/rails/initializable.rb:61:in `block in run_initializers'
# /Users/bobbert/.gem/ruby/2.7.6/gems/railties-7.0.7.2/lib/rails/initializable.rb:50:in `each'
# /Users/bobbert/.gem/ruby/2.7.6/gems/railties-7.0.7.2/lib/rails/initializable.rb:50:in `tsort_each_child'
# /Users/bobbert/.gem/ruby/2.7.6/gems/railties-7.0.7.2/lib/rails/initializable.rb:50:in `each'
# /Users/bobbert/.gem/ruby/2.7.6/gems/railties-7.0.7.2/lib/rails/initializable.rb:50:in `tsort_each_child'
# /Users/bobbert/.gem/ruby/2.7.6/gems/railties-7.0.7.2/lib/rails/initializable.rb:60:in `run_initializers'
# /Users/bobbert/.gem/ruby/2.7.6/gems/railties-7.0.7.2/lib/rails/application.rb:372:in `initialize!'
# ./spec/dummy/config/environment.rb:5:in `<top (required)>'
# /Users/bobbert/.gem/ruby/2.7.6/gems/zeitwerk-2.6.11/lib/zeitwerk/kernel.rb:38:in `require'
# /Users/bobbert/.gem/ruby/2.7.6/gems/zeitwerk-2.6.11/lib/zeitwerk/kernel.rb:38:in `require'
# ./spec/spec_helper.rb:5:in `<top (required)>'
# /Users/bobbert/.gem/ruby/2.7.6/gems/zeitwerk-2.6.11/lib/zeitwerk/kernel.rb:38:in `require'
# /Users/bobbert/.gem/ruby/2.7.6/gems/zeitwerk-2.6.11/lib/zeitwerk/kernel.rb:38:in `require'
# ./spec/awesome_engine/services/awesome_engine/pdf_exporter/termination_spec.rb:1:in `<top (required)>'
...
Finished in 0.00005 seconds (files took 10.79 seconds to load)
0 examples, 0 failures, 133 errors occurred outside of examples

在尝试不同的规范时,它会多次出现,并且它总是源于规范中的第一行,然后是 ,最后是 。spec_helper.rb:5environment.rb:5

每个规范的第一行是:

require 'spec_helper'

spec_helper.rb, Line 5

require File.expand_path("../dummy/config/environment.rb",  __FILE__)

environment.rb, Line 5

Rails.application.initialize!

这是抛出错误的 Rails 代码 ():ruby/2.7.6/gems/railties-7.0.7.2/lib/rails/engine.rb:575

573    initializer :set_autoload_paths, before: :bootstrap_hook do
574      ActiveSupport::Dependencies.autoload_paths.unshift(*_all_autoload_paths)
575      ActiveSupport::Dependencies.autoload_once_paths.unshift(*_all_autoload_once_paths)
576
577      config.autoload_paths.freeze
578      config.autoload_once_paths.freeze
579    end

我一直在关注各种关于自动加载更改的 Rails 指南,包括:

我还尝试了其他 Stackoverflow 问题中的建议:

我现在已经这样做了几个小时,但没有进展。有没有人知道这里发生了什么和/或如何解决这个问题?


更新:2023 年 8 月 28 日

因此,我决定调试并单步执行代码。

总共有 573 个初始值设定项。我放置了一个断点来跟踪调用此初始值设定项的次数。这是我发现的:initializer :set_autoload_pathsengine.rb Line 574

Rails::Application.initialize! L372
    Rails::Initializable::Initalizer.run_initializers L61
        initializer(name: :set_autoload_paths) #initializer 103 of 573
        initializer(name: :set_autoload_paths) #initializer 119 of 573
        initializer(name: :set_autoload_paths) #initializer 140 of 573
        initializer(name: :set_autoload_paths) #initializer 158 of 573
        initializer(name: :set_autoload_paths) #initializer 171 of 573
        ...

在这一点上,很明显它被多次调用。因此,我决定分析数组,看看它被调用了多少次,以及谁在调用它。这是我发现的:initializers

:set_autoload_paths=>{:count=>34, :contexts=>[#<ActionView::Railtie>, #<ActiveStorage::Engine>, #<ActionCable::Engine>, #<ActionMailbox::Engine>, #<ActionText::Engine>, #<StateMachine::RailsEngine>, #<Select2::Rails::Engine>, #<Doccex::Engine>, #<SmartListing::Engine>, #<Kaminari::Engine>, #<Devise::Engine>, #<DeviseInvitable::Engine>, #<Bootstrap::Rails::Engine>, #<Bootstrap::Switch::Rails::Engine>, #<Cocoon::Engine>, #<FontAwesome::Rails::Engine>, #<Remotipart::Rails::Engine>, #<I18n::JS::Engine>, #<Jquery::Rails::Engine>, #<Jquery::Ui::Rails::Engine>, #<JsRoutes::Engine>, #<DropzonejsRails::Engine>, #<TinyMCE::Rails::Engine>, #<BootstrapDatepickerRails::Rails::Engine>, #<Bootstrap3Datetimepicker::Rails::Engine>, #<Momentjs::Rails::Engine>, #<Uri::Js::Rails::Engine>, #<Sidekiq::Rails>, #<ActsAsTaggableOn::Engine>, #<Jscolor::Rails::Engine>, #<Tribute::Engine>, #<Doorkeeper::Engine>, #<AwesomeEngine::Engine>, #<Dummy::Application>]}

它被各种引擎调用了 34 次,其中一些来自 Rails 框架,但大多数来自引擎 gemspec 中包含的第三方库。

Ruby-on-Rails rSpec 自动加载 Ruby-on-Rails-7 Rails- 引擎

评论

0赞 smathy 8/26/2023
您链接到第 2.7 节,我假设您看到了 2.8 中的注释? - 尤其是与引擎有关?
0赞 John 8/26/2023
@smathy 你是这个意思?您是否建议我需要将初始值设定项添加到集合中?Similarly, engines can configure that collection in the class body of the engine class or in the configuration for environments.autoload_once_paths
0赞 smathy 8/26/2023
嗯,还有那部分的最后一段。我没有提出任何建议,因为我看不到你的代码,只是指出你检查你自己的代码(即确保对(和)的任何添加都是在引擎的应用程序配置的主体中完成的(而不是之后)。autoload_once_pathsautoload_paths
0赞 John 8/26/2023
@smathy谢谢,这是一个很好的建议。我看了一下,它们只设置在(相当于在应用程序中)。文档还说您可以在特定于环境的配置中设置它们(例如,)。我在任何特定于环境的配置中都没有设置任何内容。engine.rbapplication.rbconfig/environments/test.rb
0赞 Xavier Noria 8/26/2023
这发生在 Rails 内部,由于某种原因被冻结了,但它不应该是。如果这与你的应用程序有关,很难从描述中看出,但我希望它以某种方式存在,因为只有 Rails 冻结了该集合(稍后)。盲目拍摄:如果你正在使用Spring,你能停止它并尝试复制吗?ActiveSupport::Dependencies.autoload_once_paths

答: 暂无答案