ruby-on-railsrubyruby-on-rails-8

Rails uninitialized constant error only in production


I get this error when I try to start server in production mode

=> Booting Puma
=> Rails 8.0.1 application starting in production
=> Run `bin/rails server --help` for more startup options
[dotenv] Loaded .env
Exiting
C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/cref.rb:63:in `const_get': uninitialized constant Openai::Openai (NameError)

    @mod.const_get(@cname, false)
        ^^^^^^^^^^
Did you mean?  OpenAI
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/cref.rb:63:in `get'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader/eager_load.rb:173:in `block in actual_eager_load_dir'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader/helpers.rb:47:in `block in ls'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader/helpers.rb:25:in `each'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader/helpers.rb:25:in `ls'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader/eager_load.rb:168:in `actual_eager_load_dir'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader/eager_load.rb:17:in `block (2 levels) in eager_load'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader/eager_load.rb:16:in `each'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader/eager_load.rb:16:in `block in eager_load'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader/eager_load.rb:10:in `synchronize'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader/eager_load.rb:10:in `eager_load'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader.rb:430:in `block in eager_load_all'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader.rb:428:in `each'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader.rb:428:in `eager_load_all'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/application/finisher.rb:79:in `block in <module:Finisher>'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/initializable.rb:32:in `instance_exec'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/initializable.rb:32:in `run'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/initializable.rb:61:in `block in run_initializers'
        from D:/APPS/Ruby33-x64/lib/ruby/3.3.0/tsort.rb:231:in `block in tsort_each'
        from D:/APPS/Ruby33-x64/lib/ruby/3.3.0/tsort.rb:353:in `block (2 levels) in each_strongly_connected_component'
        from D:/APPS/Ruby33-x64/lib/ruby/3.3.0/tsort.rb:434:in `each_strongly_connected_component_from'
        from D:/APPS/Ruby33-x64/lib/ruby/3.3.0/tsort.rb:352:in `block in each_strongly_connected_component'
        from D:/APPS/Ruby33-x64/lib/ruby/3.3.0/tsort.rb:350:in `each'
        from D:/APPS/Ruby33-x64/lib/ruby/3.3.0/tsort.rb:350:in `call'
        from D:/APPS/Ruby33-x64/lib/ruby/3.3.0/tsort.rb:350:in `each_strongly_connected_component'
        from D:/APPS/Ruby33-x64/lib/ruby/3.3.0/tsort.rb:229:in `tsort_each'
        from D:/APPS/Ruby33-x64/lib/ruby/3.3.0/tsort.rb:208:in `tsort_each'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/initializable.rb:60:in `run_initializers'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/application.rb:440:in `initialize!'
        from D:/PROGRAMMING/RUBY/addmemore_backend/config/environment.rb:5:in `<main>'
        from config.ru:3:in `require_relative'
        from config.ru:3:in `block (2 levels) in <main>'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/rack-3.1.8/lib/rack/builder.rb:108:in `eval'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/rack-3.1.8/lib/rack/builder.rb:108:in `new_from_string'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/rack-3.1.8/lib/rack/builder.rb:97:in `load_file'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/rack-3.1.8/lib/rack/builder.rb:67:in `parse_file'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/rackup-2.2.1/lib/rackup/server.rb:354:in `build_app_and_options_from_config'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/rackup-2.2.1/lib/rackup/server.rb:263:in `app'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/rackup-2.2.1/lib/rackup/server.rb:424:in `wrapped_app'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/rackup-2.2.1/lib/rackup/server.rb:326:in `block in start'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/rackup-2.2.1/lib/rackup/server.rb:382:in `handle_profiling'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/rackup-2.2.1/lib/rackup/server.rb:325:in `start'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/commands/server/server_command.rb:38:in `start'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/commands/server/server_command.rb:145:in `block in perform'
        from <internal:kernel>:90:in `tap'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/commands/server/server_command.rb:136:in `perform'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/thor-1.3.2/lib/thor/command.rb:28:in `run'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/thor-1.3.2/lib/thor/invocation.rb:127:in `invoke_command'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/command/base.rb:178:in `invoke_command'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/thor-1.3.2/lib/thor.rb:538:in `dispatch'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/command/base.rb:73:in `perform'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/command.rb:65:in `block in invoke'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/command.rb:143:in `with_argv'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/command.rb:63:in `invoke'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/commands.rb:18:in `<main>'
        from D:/APPS/Ruby33-x64/lib/ruby/3.3.0/bundled_gems.rb:69:in `require'
        from D:/APPS/Ruby33-x64/lib/ruby/3.3.0/bundled_gems.rb:69:in `block (2 levels) in replace_require'
        from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/bootsnap-1.18.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
        from D:/PROGRAMMING/RUBY/addmemore_backend/bin/rails:4:in `<main>'

I have openai.rb in app/services/openai/ folder require "net/http" require "uri" require "json"

class OpenAI
  def initialize(api_key)
    @api_key = api_key
  end

  def generate_comments(number_of_comments, post_description, customer_query)
    # some code ...
  end
end

I also include in in application_controller.rb

require_relative "../services/openai/openai"

Erlier I soved this problems by renaming folders, modules and classesm but now it got too annoying, because class is named OpenAI, but rails tries to find Openai


Solution

  • From official guide

    By default, Rails configures Zeitwerk to inflect file names with String#camelize. For example, it expects that app/controllers/users_controller.rb defines the constant UsersController because that is what "users_controller".camelize returns.

    It means some_entity.rb should contain SomeEntity class (or module). Same for the folders, folder name should correspond to namespace (module) name

    I have openai.rb in app/services/openai/

    In this case Rails await Openai::Openai constant. If your constant is OpenAI, you should move your file to app/services/openai.rb and customize inflection

    # config/initializers/zeitwerk.rb
    loader = Rails.autoloaders.main
    
    loader.inflector.inflect(
      'openai' => 'OpenAI',
    )
    

    or

    # config/initializers/inflections.rb
    ActiveSupport::Inflector.inflections(:en) do |inflect|
      inflect.acronym 'OpenAI'
    end