Uninitialized Constant Error When Switching To Zeitwerk
Asked Answered
S

3

8

I currently have the following files in the jobs directory:

# app/jobs/importer.rb
module Imporer
  def self.valid_importers
    # Do stuff
  end
end

# app/jobs/importer/custom_import_job.rb
class Importer::CustomImportJob < ApplicationJob
  def perform
    # Do stuff
  end
end

This works without issues using the classic code loader, but when switching to Zeitwerk, I get a NameError: uninitialized constant Importer::CustomImportJob error when running rails zeitwerk:check.

I tried moving custom_import_job.rb to the jobs directory, but still received the same error. Adding app/jobs/importer to config.autoload_paths didn't help either.

Is there something wrong with the file structure or am I missing something in the Zeitwerk settings?

Swagsman answered 23/3, 2020 at 13:3 Comment(0)
S
6

After some digging around, I realized that I had the following in development.rb:

Dir[Rails.root.join('app/jobs/importer/*.rb')].each { |f| require f }

It seems this was the cause of the issue. Everything is working as expected now that it's removed!

Swagsman answered 23/3, 2020 at 20:42 Comment(3)
What was the problem though? Why was that an issue?Slashing
My guess is that the manual require interfered with the way Zeitwerk auto-loads the files, this causing the issue I faced. It probably wouldn't have been a problem if the files weren't in a folder that gets auto-loaded.Swagsman
The original problem statement is strange. First, you don't need to touch the autoload paths. Second, if those require ran successfully, Zeitwerk would just ignore the files, because their constants are already in memory (and they would be ignored on reload to, they would not be reloaded even if edited). I suspect there had to be something else. You can eager load directories with eager_load_dir instead when the loader is ready, but that is another topic.Cornetist
C
5

In case anyone else is coming here, sharing some links and context I learned via the Rails troubleshooting guide posted in another answer:

https://guides.rubyonrails.org/autoloading_and_reloading_constants.html#troubleshooting

My Rails app is on 7.0, and therefore only has zeitwerk loading. https://guides.rubyonrails.org/classic_to_zeitwerk_howto.html#applications-running-rails-7

Running rails zeitwerk:check revealed the problem I was seeing on CI, but not locally because development.rb has config.eager_load = false set in this project.

My issue was a file I had added under lib, conflicting with some deprecated config.eager_load_paths additions in application.rb.

To solve this though, it turns out my thinking to add a file to lib was outdated, and I should have just added it under app/lib. https://mcmap.net/q/156449/-load-lib-files-in-production Then I didn't need any extra require path/to/where/it/was/in/lib in my problem-causing file, and the constant was autoloaded instead via being under app.

Cyclostyle answered 28/11, 2023 at 20:41 Comment(0)
A
1

You could take a look if you app/jobs is in the path:

ActiveSupport::Dependencies.autoload_paths

extend by config.autoload_paths in config/application.rb if necessary.

More debugging information: https://guides.rubyonrails.org/autoloading_and_reloading_constants.html#troubleshooting.

  • Stop Spring. Restart the server. May also help.

Hope these helps.

Anosmia answered 23/3, 2020 at 14:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.