Namespaced concerns don't load
stanley90 opened this issue ยท 33 comments
Hi, I'm migrating an older Rails app to Zeitwerk and I'm blocked on the following problem (not even sure if to post this here or to Rails):
# app/models/document.rb
class Document
include Mongoid::Document
include ::Document::Confirmable
# and a few more
end
# app/models/concerns/document/confirmable.rb
module Document::Confirmable
extend ActiveSupport::Concern
end
When running zeitwerk:check
, none of the Document::
namespaced concerns get loaded:
# (grepped log)
Zeitwerk@rails.main: autoload set for Document, to be loaded from /Users/stanley/workspace/fundbase/app/models/document.rb
Zeitwerk@rails.main: autoload set for Document::Confirmable, to be loaded from /Users/stanley/workspace/fundbase/app/models/concerns/document/confirmable.rb
Zeitwerk@rails.main: autoload set for Document::Schedulable, to be loaded from /Users/stanley/workspace/fundbase/app/models/concerns/document/schedulable.rb
Zeitwerk@rails.main: autoload set for Document::SensitiveContent, to be loaded from /Users/stanley/workspace/fundbase/app/models/concerns/document/sensitive_content.rb
Zeitwerk@rails.main: expected file /Users/stanley/workspace/fundbase/app/models/concerns/document/confirmable.rb to define constant Document::Confirmable, but didn't
I wrapped the concern definition in begin/rescue/end
which gives
#<NameError: uninitialized constant Document::Confirmable
include ::Document::Confirmable
^^^^^^^^^^^^^>
I also tried to play a bit with prefixing the Document
with ::
to prevent a conflict with Mongoid::Document
, but that didn't help.
Yeah, the leading ::
should not be necessary because the module Mongoid::Document
does not have a constant called Document
itself. Indeed, Confirmable
would be enough.
The trace says that Zeitwerk is managing the file, but for some reason the expected constant Confirmable
is not found un Document
after loading the file.
Since this is very strange, let's try some guerrilla things first. I'd suggest adding 4 traces in the following places: first line of the file, first line in the body of Document::Confirmable
, last line of the body, last line of the file. Can you add them and check if all of them are printed?
Actually I already did that before, and that's why I put the rescue
to see why the module definition doesn't finish. Only the output before the module definition is printed, and then a few of outputs from before/in the Document definition:
--- BEFORE CONFIRMABLE
--- BEFORE DOCUMENT
--- IN DOCUMENT
--- BEFORE DOCUMENT
--- IN DOCUMENT
...
What seems to be happening is that the Document
in the module Document::Confirmable
is trying to load the Document
class (which fails to load because it tries to include the module?), but that's a circular reference?
Document
in the include
call is redundant, but should work, because the lookup path would find it in Object
, since it was just defined.
The interesting bit is that BEFORE CONFIRMABLE
is printed before BEFORE DOCUMENT
. Who is triggering the autoload of that file? Can you pp caller_locations
first thing in app/models/concerns/document/confirmable.rb?
["/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/zeitwerk-2.6.12/lib/zeitwerk/kernel.rb:38:in `require'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/zeitwerk-2.6.12/lib/zeitwerk/kernel.rb:38:in `require'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/activesupport-6.1.7.7/lib/active_support/dependencies/zeitwerk_integration.rb:49:in `require_dependency'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/mongoid-7.5.4/lib/rails/mongoid.rb:49:in `load_model'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/mongoid-7.5.4/lib/rails/mongoid.rb:25:in `block (2 levels) in load_models'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/mongoid-7.5.4/lib/rails/mongoid.rb:24:in `each'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/mongoid-7.5.4/lib/rails/mongoid.rb:24:in `block in load_models'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/mongoid-7.5.4/lib/rails/mongoid.rb:16:in `each'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/mongoid-7.5.4/lib/rails/mongoid.rb:16:in `load_models'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/mongoid-7.5.4/lib/rails/mongoid.rb:35:in `preload_models'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/mongoid-7.5.4/lib/mongoid/railtie.rb:80:in `block (2 levels) in <class:Railtie>'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/activesupport-6.1.7.7/lib/active_support/callbacks.rb:427:in `instance_exec'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/activesupport-6.1.7.7/lib/active_support/callbacks.rb:427:in `block in make_lambda'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/activesupport-6.1.7.7/lib/active_support/callbacks.rb:198:in `block (2 levels) in halting'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/activesupport-6.1.7.7/lib/active_support/callbacks.rb:604:in `block (2 levels) in default_terminator'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/activesupport-6.1.7.7/lib/active_support/callbacks.rb:603:in `catch'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/activesupport-6.1.7.7/lib/active_support/callbacks.rb:603:in `block in default_terminator'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/activesupport-6.1.7.7/lib/active_support/callbacks.rb:199:in `block in halting'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/activesupport-6.1.7.7/lib/active_support/callbacks.rb:512:in `block in invoke_before'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/activesupport-6.1.7.7/lib/active_support/callbacks.rb:512:in `each'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/activesupport-6.1.7.7/lib/active_support/callbacks.rb:512:in `invoke_before'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/activesupport-6.1.7.7/lib/active_support/callbacks.rb:105:in `run_callbacks'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/activesupport-6.1.7.7/lib/active_support/reloader.rb:88:in `prepare!'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/railties-6.1.7.7/lib/rails/application/finisher.rb:124:in `block in <module:Finisher>'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/railties-6.1.7.7/lib/rails/initializable.rb:32:in `instance_exec'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/railties-6.1.7.7/lib/rails/initializable.rb:32:in `run'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/railties-6.1.7.7/lib/rails/initializable.rb:61:in `block in run_initializers'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/3.1.0/tsort.rb:228:in `block in tsort_each'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/3.1.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/3.1.0/tsort.rb:431:in `each_strongly_connected_component_from'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/3.1.0/tsort.rb:349:in `block in each_strongly_connected_component'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/3.1.0/tsort.rb:347:in `each'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/3.1.0/tsort.rb:347:in `call'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/3.1.0/tsort.rb:347:in `each_strongly_connected_component'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/3.1.0/tsort.rb:226:in `tsort_each'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/3.1.0/tsort.rb:205:in `tsort_each'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/railties-6.1.7.7/lib/rails/initializable.rb:60:in `run_initializers'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/railties-6.1.7.7/lib/rails/application.rb:391:in `initialize!'",
"/Users/stanley/workspace/fundbase/config/environment.rb:5:in `<top (required)>'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/zeitwerk-2.6.12/lib/zeitwerk/kernel.rb:38:in `require'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/zeitwerk-2.6.12/lib/zeitwerk/kernel.rb:38:in `require'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/activesupport-6.1.7.7/lib/active_support/dependencies.rb:332:in `block in require'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/activesupport-6.1.7.7/lib/active_support/dependencies.rb:299:in `load_dependency'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/activesupport-6.1.7.7/lib/active_support/dependencies.rb:332:in `require'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/railties-6.1.7.7/lib/rails/application.rb:367:in `require_environment!'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/railties-6.1.7.7/lib/rails/application.rb:533:in `block in run_tasks_blocks'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:281:in `block in execute'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:281:in `each'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:281:in `execute'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:219:in `block in invoke_with_call_chain'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:199:in `synchronize'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:199:in `invoke_with_call_chain'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:243:in `block in invoke_prerequisites'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:241:in `each'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:241:in `invoke_prerequisites'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:218:in `block in invoke_with_call_chain'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:199:in `synchronize'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:199:in `invoke_with_call_chain'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/task.rb:188:in `invoke'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/application.rb:160:in `invoke_task'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/application.rb:116:in `block (2 levels) in top_level'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/application.rb:116:in `each'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/application.rb:116:in `block in top_level'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/application.rb:125:in `run_with_threads'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/application.rb:110:in `top_level'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/railties-6.1.7.7/lib/rails/commands/rake/rake_command.rb:24:in `block (2 levels) in perform'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/application.rb:186:in `standard_exception_handling'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/railties-6.1.7.7/lib/rails/commands/rake/rake_command.rb:24:in `block in perform'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/rake-13.0.6/lib/rake/rake_module.rb:59:in `with_application'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/railties-6.1.7.7/lib/rails/commands/rake/rake_command.rb:18:in `perform'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/railties-6.1.7.7/lib/rails/command.rb:50:in `invoke'",
"/Users/stanley/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/railties-6.1.7.7/lib/rails/commands.rb:18:in `<top (required)>'",
"bin/rails:5:in `require'",
"bin/rails:5:in `<main>'"]
require_dependency
and load_model
are suspicious there. Is as if Mongoid was trying to load the concern directly using require_dependency
, without going through the model first. That does not seem right, why would Mongoid be loading a file that is related only indirectly?
I cannot follow that hint right now, not familiar with Mongoid either. Just pointing it out in case it helps you investigate further.
The calls to require_dependency
are invoked because of preload_models: true
(in Mongoid config), which is needed for STI.
But maybe that can be replaced with https://guides.rubyonrails.org/autoloading_and_reloading_constants.html#option-2-preload-a-collapsed-directory. I'll play with it tomorrow.
@stanley90 yes, we have it.
As you guessed, there is a circularity. This is a limitation of the current require_dependency
in Rails, I should revise it.
Indeed, if preloading models is done just to load that STI, the technique you linked to is going to work and, assuming there are more models, it is going to do less things.
Okay, so I disabled Mongoid's preload_models
and cleaned up the collapsed and eager-loaded directories. This part seems to work, but still a lot of mess ahead.
Do you think I should post about this situation to Mongoid's JIRA too?
Which is the mess?
Occasional wrong namespacing, some require
statements, etc. (10-year old app...)
Btw I realized you're on this year's Euruko, I'm buying you a beer in Sarajevo for the quick help ๐ ๐ป
Btw, if I have some core extensions, should I eager_load
or require
them in the initializer?
@stanley90 up for that beer! :)
If core extensions is code that reopens already existing classes/modules, that is not managed by the autoloaders, therefore it should be require
d normally, the autolaoder API cannot be used. If the code was mixed with autoloaded code in the project tree, the autoloader should be configured to ignore it.
So (almost) everything works now, but found one more issue. According to the documentation on STI I did
unless Rails.application.config.eager_load
Rails.application.config.to_prepare do
Rails.autoloaders.main.eager_load_dir(Rails.root.join('app/models'))
end
end
but if I try the Rails console and Rspec with config.eager_load = true
, the model subclasses are not loaded (zeitwerk:check
doesn't complain, though). I could remove the unless
condition, but it smells a bit.
Let me just say that you'd normally eager load the collapsed subdirectory of app/models
that contains the STI, if there is one. Just because it would load less code than eager loading all the models. However, if loading the entire app/models
was on purpose, that is fine of course, a remark just in case it wasn't :).
What you say re eager loading is certainly strange. Is there anything in app/models
eager loaded if config.eager_load
is true
?
How do I check that root models are eager-loaded (vs auto-loaded when I reference them)?
If you execute in a shell bin/rails r 1
, the application boots, runner
executes the 1
script, and exits.
Eager loading happens at boot time.
Okay so I did rails r 'pp Mongoid.models'
and only a very few models were printed (maybe they're referenced and autoloaded somewhere), but most models are not.
Interestiing. Can you share the ouput of this?
bin/rails r 'p Rails.autoloaders.main'
I suspect things are configured in some particular way.
and the configuration for app
is
%w[
activities assets alpha channels emails export export/export_id exposures filters holdings images native notes
portfolios sets tracking_schedule
].each do |dir|
Rails.autoloaders.main.collapse(Rails.root.join('app/models', dir))
end
%w[alpha connection_requests].each do |dir|
Rails.autoloaders.main.collapse(Rails.root.join('app/modules', dir))
end
unless Rails.application.config.eager_load
Rails.application.config.to_prepare do
Rails.autoloaders.main.eager_load_dir(Rails.root.join('app/models'))
end
end
Thank you, happy to see the app makes an extensive use of collapsed directories, was worth the work!
I don't quite see what you say in that autoloader inspection. The ivar @autoloads
contains constants that have autoloads set but have not been triggered. If app/models
was not eager loaded, we'd see quite a bit of autoloads for them (the ones at the top level).
On the other hand @to_unload
has the constants that have been loaded so far (if reloading is enabled). I see 274 occurrences of app/models
there.
Can you prove that there exists a model that is not eager loaded? Can you put a trace in a model and do not have it printed? It has to be a model, not a concern. While concerns are in subdirectories, they are considered to be separate trees.
Thank you, happy to see the app makes an extensive use of collapsed directories, was worth the work!
I wish zeitwerk existed earlier and we'd structure the app better ๐
Can you prove that there exists a model that is not eager loaded? Can you put a trace in a model and do not have it printed? It has to be a model, not a concern. While concerns are in subdirectories, they are considered to be separate trees.
Sure. Only these are loaded:
rails r 'pp Mongoid.models'
--- Fund
--- Asset
Running via Spring preloader in process 34012
[Mongoid::GlobalDiscriminatorKeyAssignment::InvalidFieldHost,
DataMigration,
Mongoid::GridFs::Fs::File,
Mongoid::GridFs::Fs::Chunk,
FundClass,
Asset,
TrackedField,
FundUniverse,
TimeWithUnit,
OrganizationRole,
MasterOption,
LiquidityInfo,
SystemSetting,
Subscription::Trade,
User]
E.g. Asset
has descendants Asset < Fund < HedgeFund
, you see the --- Fund
and --- Asset
are printed, but --- HedgeFund
is not. And interestingly, Asset
is in the list of models, but Fund
is not.
Also tried printing:
rails r 'pp Asset.descendants'
[Fund]
OK, we are progressing.
If we look at the state of the autoloader, HedgeFund
has been loaded. It is in the @to_unload
collection:
"HedgeFund"=>
["/Users/stanley/workspace/fundbase/app/models/assets/hedge_fund.rb",
[Object, :HedgeFund]],
So the question is, how is Mongoid.models
implemented?
I don't know if the descendants
call is relevant because you need to install some sort of descendants tracking for that to work (like ActiveSupport::DescendantsTracker). Is Mongoid supposed to do that?
Mongoid seems to track models by tracking the inclusion of Mongoid::Document
:
module Mongoid
module Document
included do
Mongoid.register_model(self)
end
end
So, only those classes with actual includes are registered, subclasses aren't.
See this script for example:
require 'mongoid'
class Foo
include Mongoid::Document
end
class Woo < Foo
end
class Bar
include Mongoid::Document
end
class Baz < Bar
end
pp Mongoid.models # => [Mongoid::GlobalDiscriminatorKeyAssignment::InvalidFieldHost, Foo, Bar]
Woo
and Baz
are not included.
Yes, I suspected Mongoid.models
might do something specific.. But anyway, if I'm back to simple things, I get:
rails r 'p Asset.subclasses; p Fund.subclasses' ๎ฒ โ ๎ณ 3.1.4 ๏ ๎ณ 12.22.9 ๎
--- Fund
--- Asset
Running via Spring preloader in process 37880
[Fund]
[]
You say you see the HedgeFund
loaded, but it's not printed here ๐ค
When things get weird in a way that defies logic, I remove Spring from the equation. Could you try?
Could you also enable logging and grep by that class name? Let's work with Spring disabled until we understand what is going on.
Spring disabled. Grepped output (I didn't grep for "fund" because that's in a million places).
$ rails r 'p Asset.subclasses; p Fund.subclasses' | egrep -i 'hedgefund|hedge_fund|asset|---'
Zeitwerk@rails.main: autoload set for Asset, to be loaded from /Users/stanley/workspace/fundbase/app/models/assets/asset.rb
Zeitwerk@rails.main: autoload set for EtFund, to be loaded from /Users/stanley/workspace/fundbase/app/models/assets/et_fund.rb
Zeitwerk@rails.main: autoload set for FofFund, to be loaded from /Users/stanley/workspace/fundbase/app/models/assets/fof_fund.rb
Zeitwerk@rails.main: autoload set for Fund, to be loaded from /Users/stanley/workspace/fundbase/app/models/assets/fund.rb
Zeitwerk@rails.main: autoload set for HedgeFund, to be loaded from /Users/stanley/workspace/fundbase/app/models/assets/hedge_fund.rb
Zeitwerk@rails.main: autoload set for MutualFund, to be loaded from /Users/stanley/workspace/fundbase/app/models/assets/mutual_fund.rb
Zeitwerk@rails.main: autoload set for OtherAlternative, to be loaded from /Users/stanley/workspace/fundbase/app/models/assets/other_alternative.rb
Zeitwerk@rails.main: autoload set for PrivateEquityFund, to be loaded from /Users/stanley/workspace/fundbase/app/models/assets/private_equity_fund.rb
Zeitwerk@rails.main: autoload set for Admin::AssetsController, to be loaded from /Users/stanley/workspace/fundbase/app/controllers/admin/assets_controller.rb
--- Fund
--- Asset
Zeitwerk@rails.main: constant Asset loaded from file /Users/stanley/workspace/fundbase/app/models/assets/asset.rb
Zeitwerk@rails.main: constant Fund loaded from file /Users/stanley/workspace/fundbase/app/models/assets/fund.rb
I tried to reproduce this with a minimal app and could not. That is, I created a folder app/models/assets/foo.rb
, collapsed app/models/assets
, and eager_load_dir('app/models')
. It eager loaded the file.
Can you reproduce with a minimal app?
BTW, I find very hard to believe that the traces do not show HedgeFund
loaded and at the same time that @to_unload
in the autoloader inspection has the constant. If that turns out to be the case, I'll invite you to a drink next time we have the opportunity :).
Soo I think I figured it out and it's all my mistake. The order is the problem:
# application.rb
config.eager_load = true # this is what I did just for testing - wrong place!
...
unless Rails.application.config.eager_load # wrong place again, should be later, in an initializer
Rails.application.config.to_prepare do
Rails.autoloaders.main.eager_load_dir(Rails.root.join('app/models'))
end
end
# development.rb
config.eager_load = false # should change this for testing instead
Besides the wrong order of things happening, eager_load
was true
during a part of initialization and false
during another part (set both in application.rb and development.rb).
Correct order is: application.rb, development.rb, initializer
The drinks are on me then ๐
Ahhhh my friend! ๐
@stanley90 how's the migration going? Do you have autoloading in place or need more help?
Seems to be finished and working fine, a bit stuck in QA ๐ But I think we can close this issue. Thanks for the help and I'll catch you in Sarajevo ๐