There is a programmatical way to detect Zeitwerk::NameError when upgrading to Rails 6?
Asked Answered
H

2

4

I am currently migrating an old Rails application to Rails 6.

It seems that some files in the project are not consistent with the classes defined in it. I don't see this error when running the tests of the application, but after deploy I receive errors like:

 Zeitwerk::NameError: expected file /app/my?_/app/lib/multi_io.rb to define constant MultiIo, but didn't

In previous SO questions I could find suggestions to:

I am not looking for a workaround so I corrected the file raising the exception.

I would like to find a programmatical way to detect all inconsistent path/class names without running the application in production mode.

So far, three options came to my mind:

  1. A rake task to validate the autoloading (which is not provided by the gem). Does it exists? Would you have a snippet to run from the rails console in development env instead?
  2. A rubocop cop or another static code analyser. There is any?
  3. Force the eager load in the test environment

What it the suggested approach to validate my code without requiring several iterations/deployments?

thank you very much in advance

Henebry answered 16/9, 2020 at 20:55 Comment(2)
Have you tried running the zeitwerk:check task? It detects autoloading issues, including things like issues with constant names (classic/underscore vs. zeitwerk/camelize).Blond
this works! thank you. If you add it as an answer, I will accept it!Henebry
B
10

You can check the autoload compatibility of a project with the zeitwerk::check task:

$ bin/rails zeitwerk:check
Hold on, I am eager loading the application.
All is good!

It exercises all the autoload paths and will flag issues such as those caused by the change in constant name inference (such as those with acronyms). The task doesn't appear to be widely advertised or documented except in the upgrade guide. But, I actually use it sometimes to just flush out constant naming issues in the project generally (i.e., where the class doesn't match the file).

Blond answered 16/9, 2020 at 22:4 Comment(0)
B
1

@rmlockerd Described one of the best tools bin/rails zeitwerk:check for this in his answer here.

The other articles I found informative were:

The process I took was to run bin/rails zeitwerk:check fix an error, run it again until I saw "All is good". After that worked through errors reported by our spec tests.

One general problem to fix is if a folder is not within the Rails default file structure, Zeitwerk will not be able to find it when autoloading. We had a folder named "services" (app/services) that needed to be added to the autoload path within the application.rb file like:

config.autoload_paths += %W(#{config.root}/app/services/)

Error:

Expected file path/file_name.rb to define constant FileName

Fix: remove any require or require_relative in other files referencing where the class is defined (Zeitwerk doesn't need them).

Error (class is defined within a module of a sub directory):

NameError: uninitialized constant SubFile::ClassName

Fix:

Detailed in another S/O answer. Whenever method is used within sub folders structure the call as Folder::SubDirectory::Class.method_call

Goodluck!

Baht answered 15/9, 2021 at 4:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.