Search code examples
ruby-on-railsrubyruby-on-rails-5

Rails 5 autoloading issue in production


I have a hard time understanding an issue with Rails autoloading.

So I have a controller which is located in a folder named api. The constroller is declared as class Api::TestController.

In another folder, I have a file called app/my_folder/service_name/api.rb

In production, I get this error : load_missing_constant': Unable to autoload constant Api, expected /app/my_folder/service_name/api.rb to define it (LoadError)

application.rb has this line :

config.autoload_paths += Dir[Rails.root.join('app', 'my_folder', '{**/}')]

I have no issues in development.

Why is this happening ?


Solution

  • Its happening since the auto load paths are only used for auto loading. In order for your class to be loaded in production you need to augment the eager_load_paths as well:

    config.eager_load_paths += Dir[Rails.root.join('app', 'my_folder', '{**/}')]
    

    However this isn't exactly a great practice - any directory in app is automatically used as a root directory. What you're doing is adding every subdirectory of a given directory as root directories.

    Using the scope resultion operator (class Api::TestController) for namespace definition should also be avoided as it leads to suprising constant lookup behavior and is the source of autoloading bugs. Instead you should nest the class explicitly and setup an inflection for the acronym:

    # config/initializers/inflections.rb
    ActiveSupport::Inflector.inflections(:en) do |inflect|
      inflect.acronym 'API'
    end
    
    # every time you use Api as a constant name a kitten dies.
    module API
      class TestController
        puts Module.nesting.inspect # [TestController::API, API] 
      end
    end