-
Notifications
You must be signed in to change notification settings - Fork 21.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rails 6.1 Constant autoloading not working in environment configuration files #40904
Comments
@samstickland I think Rails 6.1 doesn't eager load In the
|
It's in
Additionally if I remove the line from |
Thanks for the issue, and for the example repo. I believe this was an intentional breaking change for Rails 6.1. This would have worked in Rails 6.0, but it would have output a deprecation warning. I double checked using your example repo back on Rails 6.0.3.4 and I can see this in log/development.log: DEPRECATION WARNING: Initialization autoloaded the constants MyNamespace and MyNamespace::MyClass.
Being able to do this is deprecated. Autoloading during initialization is going
to be an error condition in future versions of Rails.
Reloading does not reboot the application, and therefore code executed during
initialization does not run again. So, if you reload MyNamespace, for example,
the expected changes won't be reflected in that stale Module object.
These autoloaded constants have been unloaded.
Please, check the "Autoloading and Reloading Constants" guide for solutions.
(called from <main> at rails-6.1-constant-resolution-issue/config/environment.rb:5) In general I would recommend addressing all deprecation warnings before upgrading to the next version. |
Actually, I still see that deprecation warning in the code, so I am probably missing something here. |
@composerinteralia Oh interesting.. The deprecation warning made it into the log, but I would had expected to had seen it printed before the console startup too. As it was I had entirely missed it. |
Looks like 43863bf changed this behavior, so I think I was wrong about it being an intentional breaking change. But it would have eventually been an intentional breaking change 🤣. |
I'm also experiencing this issue inside of |
@glinesbdev In my case I was able to move the objects referenced out of the autoloading paths (we keep autoloading off on If that's not possible you might be able to move required setup to an initializer instead? |
The problem is that we use the code in that path in our application as well so it needs to be auto loaded. The other problem is that I need to use that code to add production env config. I'll have to research / test setting those settings in initializers instead of environments. |
cc @fxn |
Yes. The reason for this is explained in the warning message.
Options:
|
@glinesbdev Please do not move that to the initializers, it is still the same, and it will err in the future. The err turn arrived before to |
@fxn is the autoload disable in 6.1 already or only will be in 6.2? The issue here is that people are getting |
The warning shipped with 6.0.0. In 6.1 you cannot autoload in We can close this one. |
I actually didn't understand wrap the code in a to_prepare block documentation until just now. I think because i didn't read the setup example above and i nope'd when i saw examples with global assignments In my case different environments use different formatting, but also instantiated and referenced in other contexts outside environment booting. # staging.rb
config.log_formatter = SpecialJsonFormatter.new # app/lib/special_json_formatter.rb You might see a lot of duplicates of this tickets rolling in (ex, see suggested autoloading below), so it might help modify the title a bit to help search. I only got here after realizing it was unique to environment file usage, and double checking release notes. I just assumed stale/corrupted bootsnap cache, or documented zeitwerk change, but |
@rromanchuk Ah! In that case the proper solution is to move your code to When the application boots, Let's imagine railtie class Foo::Service
cattr_accessor :endpoint
end OK. In general, the internal way to represent things is not exposed, the public interface to it goes via initializer "init.foo" do
Foo::Service.endpoint = config.foo.endpoint
end so to speak. That is tied to the boot process, initializers run only once. If you change So, better |
@rromanchuk Let me add that I explained this to help understand the reason why this is the best option. However, I do not assume you had to know this, I believe this is not well documented. Maybe we need a clear contract of what can be done and what cannot be done at each stage of the boot process. |
I've run into this exact issue, helpful to find it it in github, great! Still a bit confused about what's going on. Let's say I have something in OK, it won't autoload.... do I have any other way to use it? I think it's not allowed to somehow "manually" load things that are set to be auto-loaded... So Rails 6.1 just comes with a restriction that you can't reference any files controlled by auto-loading in environment configuration files? This is challenging for me. I do a lot of this, and it's hard for me to avoid doing it and stay DRY. I hadn't noticed the deprecation in rails 6.0, but went and looked at my logs and confirmed it was there.
OK, so don't do that as a workaround. So... there is no workaround? I'm just not allowed to reference any of my app's classes in initialization/configuration code? One common case I am seeing in doing this is setting configuration for a gem This is... challenging. I'm rather confused. |
This makes it easier to use in working and non-deprecated way in Rails initialization code, which is one of it's main use cases. Changes to Rails auto-loading/zeitwerk make it so that you should not be referencing auto-loaded code in Rails configuration/initialization phases. rails/rails#40904 As we now explicitly require kithe/config_base in the kithe/engine file, this change should be transparent and backwards-compatible.
The Rails Guide referenced in the deprecation notice is pretty good, recommended. I'm starting to wrap my head around it. https://guides.rubyonrails.org/autoloading_and_reloading_constants.html#reloading-and-stale-objects |
OK, so I want to reference some custom logic in config/initializers. It can't be auto-loaded, so I put my custom class in local app I'm having trouble figuring out how to reference that in eg If anyone has any thoughts or hints for patterns here, it would be appreciated. Makes sense not to reference auto-loaded things in config/initializer; but it makes sense that we should be able to reference custom local classes somehow, and i'm having trouble with it. |
@jrochkind The part of the boot process that is relevant for this happens when |
@fxn Thanks! Weirdly, I could not get this working in the "naive" approach, I'm not sure if that is expected or not. But I did figure out a way that worked for me. I have an app we'll call MyApp. It has a class I tried putting Maybe this is actually expected, at the point It appears to work if I added But since I'm also using MyApp::Helper in initializers, which aren't tied to any particular environment, I really wanted to put the Putting it in a
Sorry if this is distracting or if I'm still confused about something. But it took me a day or so to get through this and figure out what would work, so thought I would leave this for others. Also curious for any feedback. I think advice and patterns for moving custom classes needed in boot to non-auto-loaded locations will be a thing others find themselves needing. |
@jrochkind before the line with the class MyApp::Application < Rails::Application
# lib is in $LOAD_PATH now.
require "my_app/helper"
...
end Alternatively, you can also use require_relative "../lib/my_app/helper" but it is, perhaps, uglier. |
Thanks @fxn! Confirmed that worked, the require inside Application class body. I don't know why I didn't try that first, I thought I did, but clearly not! It is a little bit more straightforward than the Hopefully this will be findable and help others trying to move from using auto-loaded classes in configuration/initialization process. The little gotchas made it take more time than I thought it would. |
Steps to reproduce
Referencing an autoloaded constant in an environment configuration (e.g.
config/environments/development.rb
) results in aNameError
("uninitialized constant"). This worked correctly in Rails 6.0.3.4.An example repo demonstrating the problem is available here: https://github.com/samstickland/rails-6.1-constant-resolution-issue . Running "rails c" is not possible in this repo with Rails 6.1. The first commit in the repo is the result of "rails new" and the second demonstrates the issue
Expected behavior
The constant should be resolved
Actual behavior
The constant is not resolved.
System configuration
Rails version: 6.1.0
Ruby version: 2.7.2
The text was updated successfully, but these errors were encountered: