Search code examples
ruby-on-railsruby

rails: NameError uninitialized constant


I'm new to Rails and I'm trying to create a custom logger. I've placed my custom logger class in app/custom_logger/custom_log.rb as follows:

module CustomLogger
  class CustomLog
    def self.info
      puts 'called'
    end
  end
end

In my AccountController (app/controllers/account_controller.rb), I'm trying to use this custom logger:

class AccountController < ApplicationController
  def get
    CustomLogger::CustomLog.info
    render status: :ok
  end
end

However, when I send a request to this controller, I get the following error:

uninitialized constant AccountController::CustomLogger

I tried adding include CustomLogger in app/controllers/application_controller.rb and using require_relative '../custom_logger/custom_log.rb', but neither of these approaches worked.


Solution

  • With this file structure app/custom_logger/custom_log.rb, zeitwerk is expecting you to define CustomLog:

    # root directory
    #       |
    # vvvvvvvvvvvvvvvvv
    # app/custom_logger/custom_log.rb
    #                   ^^^^^^^^^^
    #                      |
    class CustomLog # -----'
    end
    

    File structure have to correspond to module/class names relative to a root directory. Rails will automatically configure any directory directly under app to be a root directory by adding it to autoload_paths.

    If you want to have CustomLogger::CustomLog then you need to make an extra directory under app, name it whatever you like:

    # root directory
    #      |
    # vvvvvvvvvvv
    # app/loggers/custom_logger/custom_log.rb
    #             ^^^^^^^^^^^^^ ^^^^^^^^^^
    #                      |        |
    module CustomLogger # -'        |
      class CustomLog   # ----------'
      end
    end
    

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


    Note, that you cannot use this logger when application is booting up, that goes for all reloadable code (everything in autoload_paths). You could set up autoload_once_paths if you want to use it in an initializer, or you can always put it in your lib directory and require it.

    https://guides.rubyonrails.org/autoloading_and_reloading_constants.html#autoloading-when-the-application-boots