Reputation: 22670
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
This all worked perfectly with Rails 6.1 using Zeitwerk and defaults set for 6.1:
config.load_defaults 6.1
config.autoloader = :zeitwerk
But upgrading to Rails 7, keeping defaults at 6.1 (and obviously using Zeitwerk), it is not working:
/Users/brandon/Code/Rails/portal/config/initializers/features.rb:105:in `<main>': uninitialized constant Report (NameError)
If I manually require
the Report
model, it doesn't solve the problem. Instead I just get
/Users/brandon/Code/Rails/portal/app/models/report.rb:1:in `<main>': uninitialized constant ApplicationRecord (NameError)
Did you mean? ApplicationConfig
So it seems like there's a whole lot of stuff that has not yet been loaded at this point in the Rails boot-up process, but which would have been loaded at this point running on Rails 6.1.
Adding require 'rails/all'
doesn't change anything.
(In case it's not obvious, this applies to all of my models, and lots of other things. None of the classes I have previously had available during initialization are now available on Rails 7.)
How can I fix this and make everything work on Rails 7?
Upvotes: 8
Views: 3795
Reputation: 402
You should wrap your initializer in a Rails.application.config.to_prepare
block.
In your case:
Rails.application.config.to_prepare do
Report.all.each do |report|
default_to_enabled(report&.feature_name)
end
end
(Thank you @Xavier for pointing to this section)
Upvotes: 10
Reputation: 61
I'm using rails 7.0.4
> bundle show | grep "rails ("
* rails (7.0.4)
I tried the following and I was able to load a model inside initializer file
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
Basically this loads this particular initializer only after all other configurations are loaded.
Lemme know if this worked :D
Upvotes: 1
Reputation: 2324
No, autoload_once_paths
is not what you want, because reloading won't update the models.
Please, read this section of the autoloading guide.
Upvotes: 3
Reputation: 22670
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.
The only thing I've found so far is to work around the limitation rather than try to resolve it (or one might say "work with the grain instead of against it") by adding this in config/application.rb
instead of the code in my initializer:
config.after_initialize do
Report.all.each do |report|
default_to_enabled(report&.feature_name)
end
end
Upvotes: 3