Search code examples
ruby-on-railszeitwerk

Rails module constant did not work with Zeitwerk


I have this code in /lib/my_app/version.rb

module MyApp
  VERSION = '3.0.7'
end

When I tried this MyApp::VERSION, I saw this error: uninitialized constant MyApp::VERSION.

Then I tried to add config.eager_load_paths << Rails.root.join("lib"), and a new error happened: expected file /Users/Documents/big_app/lib/my_app/version.rb to define constant MyApp::Version, but didn't (Zeitwerk::NameError)

The only solution that worked for me was to add require_relative '../lib/my_app/version' to application.rb config file. But I think it's not the right solution.

Any idea about this issue?


Solution

  • If what you're looking to do is just version your Rails application you can just keep it simple and place the constant in config/application.rb which is required in the boot process anyways and includes a module encapsulating your application.

    # ...
    module MyApp
      VERSION = '3.0.7'
      class Application < Rails::Application
        # Initialize configuration defaults for originally generated Rails version.
        config.load_defaults 7.0
      end
    end
    

    The only solution that worked for me was to add require_relative '../lib/my_app/version' to application.rb config file. But I think it's not the right solution.

    It's less wrong than your other attempt.

    Zeitwerk is really for loading the classes and modules in your application. Constants that are simple scalar values do not need a separate file and autoloaded constants are not available at boot time.

    In gems you typically include the version in the lib/my_gem.rb file which is largely boilerplate anyways. This doesn't make much sense to emulate in a Rails app though.

    If you really want a separate file which is done in some gems simply to reduce the amount of churn in the version history of the gemspec file then you just require it manually.

    require Rails.root.join('lib/my_app/version')
    

    However again, does this actually make any sense in the context of a Rails app?

    lib in Rails is commonly used for code that doesn't quite fit into /app and should not be autoloaded. It's the purgatory that code lives in until it's extracted into a separate gem. It's not a very obvious place to place something that's just config.