zeitwerk: Failed to get origin class after including gem using zeitwerk
I am upgrading rails. My project has a custom gem and has a controller inside (with namespace). But if I include the gem I can not get the controller (with same namespace) in the rails main project successfully (which I can get that controller without including the gem). Any idea or clue about this?
Many Thanks. ðŸ˜
Detail:
(In Gem) https://github.com/crokobit/at-gem-controllers-for-test/ lib/at-gem-controllers/api_v1/base_controller.rb
Setting of zeitwerk in gem: https://github.com/crokobit/at-gem-controllers-for-test/blob/master/lib/at-gem-controllers.rb
class Controllers
end
require 'rubygems'
require 'bundler/setup'
Bundler.require(:default)
require 'zeitwerk'
loader = Zeitwerk::Loader.for_gem
loader.inflector.inflect(
"at-gem-controllers" => "Controllers",
)
loader.push_dir("#{__dir__}/at-gem-controllers")
loader.setup
(In Rails) https://github.com/crokobit/test-zeitwerk
has controller: app/controllers/api_v1/ping_controller.rb
I found that when I am including the at-gem-controllers gem, I will not get the ApiV1::PingController but I can get the Api::BaseController. however, if I remove the gem, I will get the ApiV1::PingController.
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 21 (13 by maintainers)
OK, I finally consider this to be a bug. Let me explain.
Documentation says you should load shared namespaces beforehand, and your application is doing so by loading the gem. The gem provides the namespace, and as far as client code is concerned, the namespace is there. It does not matter if the constant exists as such, or it only has an autoload defined for it. Zeitwerk supported the first case, but not the second one.
If the gem says all you need to do to function is requiring the top-level file, that should be it. It does not matter whether that’s true because it uses Zeitwerk, or because it issues manual
require
calls, or because it issues manualautoload
calls. The fact is that by requireing the top-level file the namespace is available.So, I have added support for this use case in https://github.com/fxn/zeitwerk/commit/1862b6feadd564f833dd124834647c2401add310.
By now,
loader.eager_load
is a workaround, but in the next release you’ll be able to delete it.Thanks!
loader.eager_load
only eager loads the files managed byloader
.It all works out of the box if different loaders manage different namespaces, which is the common case. You only need to be careful in the documented case of shared namespaces, and this case does not depend on lazy/eager loading, it has to be addressed anyway.