【问题标题】:Rails Model no longer available in initializer after upgrade to Rails 7.0Rails Model no longer available in initializer after upgrade to Rails 7.0
【发布时间】:2022-12-15 07:41:44
【问题描述】:

I have a Rails initializer (features.rb) that must access a model (Report).

Report.all.each do |report|
  default_to_enabled(report&.feature_name)
end

使用 Zeitwerk 和 6.1 的默认设置,这一切都与 Rails 6.1 完美配合:

config.load_defaults 6.1
config.autoloader = :zeitwerk

但是升级到 Rails 7,将默认值保持在 6.1(并且显然使用 Zeitwerk),它不起作用:

/Users/brandon/Code/Rails/portal/config/initializers/features.rb:105:in `<main>': uninitialized constant Report (NameError)

如果我手动requireReport模型,它并不能解决问题。相反,我只是得到

/Users/brandon/Code/Rails/portal/app/models/report.rb:1:in `<main>': uninitialized constant ApplicationRecord (NameError)
Did you mean?  ApplicationConfig

因此,在 Rails 启动过程的这一点上,似乎还有很多东西尚未加载,但在 Rails 6.1 上运行时,这些东西会在此时加载。

添加 require 'rails/all' 不会改变任何内容。

(如果不是很明显,这适用于全部我的模型,还有很多其他的东西。我以前在初始化期间可用的所有类现在在 Rails 7 上都不可用。)

我怎样才能解决这个问题并使一切都在 Rails 7 上运行?

【问题讨论】:

  • 如果它增加了你的洞察力......我有两个 Rails 7 应用程序,我只是在每个应用程序中添加了一个测试初始化​​程序以确定在运行初始化程序时是否加载了 app/models 中的模型......在两个应用程序中模型是不是加载。您可能需要在 application.rb (guides.rubyonrails.org/configuring.html#using-initializer-files) 中配置一个 config.after_initialize 块并在那里运行您的 init。
  • 是的,谢谢,我刚刚发现这是一个解决方案,当我发现您的评论时正要将其发布在这里。我不知道这是唯一还是最好的解决方案,但它对我有用。
  • 当然,如果其他人提出更好的答案,我会接受他们的答案而不是我自己的。

标签: ruby-on-rails ruby ruby-on-rails-6 ruby-on-rails-7 ruby-on-rails-6.1


【解决方案1】:

While poking around in the Autoloading guide it occurred to me to try this in config/application.rb:

config.autoload_once_paths << "#{root}/app/models"

but while that made my Report class available, it also created a bigger new problem with Zeitwerk.

到目前为止我发现的唯一一件事是通过在config/application.rb而不是我的代码中添加它来解决这个限制而不是试图解决它(或者有人可能会说“与谷物一起工作而不是反对它”)初始值设定项:

config.after_initialize do
  Report.all.each do |report|
    default_to_enabled(report&.feature_name)
  end      
end

【讨论】:

  • 早期调用模型(初始化器)一直是问题的根源,不仅是自定义代码,还有一些 gem 提供的模型——这样做意味着数据库应该在任何时候默认可用——即使在 CI 期间构建并且这并不总是可取的, after_initialize afaik 是一个很好的折衷方案,但尽量在早期阶段保持模型加载
【解决方案2】:

不,autoload_once_paths 不是您想要的,因为重新加载不会更新模型。

请阅读自动加载指南的this section

【讨论】:

    【解决方案3】:

    我正在使用 rails 7.0.4

    > bundle show | grep "rails ("
      * rails (7.0.4)
    

    我尝试了以下操作,并且能够在初始化文件中加载模型

    Rails.configuration.after_initialize do
      # Accessing BlockedIp model
      bad_ip = BlockedIp.first.ip
    
      Rack::Attack.blocklist("Block IPS") do |req|
        req.remote_ip == bad_ip.to_s
      end
    end
    

    基本上,只有在加载所有其他配置后,才会加载这个特定的初始化程序。

    让我知道这是否有效:D

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-06
      • 2014-08-20
      • 2016-05-08
      • 2022-12-19
      • 1970-01-01
      • 2023-02-24
      • 2022-12-19
      • 1970-01-01
      相关资源
      最近更新 更多