2

I have two separate Rails applications

  • one just exposes an API (henceforth termed as API-app) and

  • another one acts as an Administration Portal (henceforth termed as AdminPortal) for managing the data in API-app.

Both are presently running on Rails 4.2.5.1 on staging as well as production environments. However on a staging_experimental environment I upgraded both the applications to Rails 5.0.0.1. I have rspecs for the both the applications and the spec suite in both the applications is passing and Capistrano deployment goes success. However when trying to send request to API-endpoint in API-app I face a runtime error

NameError (uninitialized constant Api::BaseController::ApiTokenAuthentication)

/lib/api_token_authentication.rb

module ApiTokenAuthentication
  <some module_functions defined here>
end

and the module functions are accessed in my controller in following manner:

class Api::BaseController < ActionController::Base
  def authenticate!(user)
     ApiTokenAuthentication.my_module_function_here(user)
  end
end

The same kind of runtime-error NameError (uninitialized constant ...) errors are also encountered in AdminPortal too and they refer to the code placed in AdminPortal's codebase's lib folder. For e.g.

NameError (uninitialized constant MyApiApp::Api):

NameError (uninitialized constant MyApiApp::Api::Get):

NameError (uninitialized > constant MyApiApp::Api::Post):

/lib/my_api_app

/lib/my_api_app/api.rb

module MyApiApp
  module Api
  end
end

/lib/my_api_app/api/get.rb

module MyApiApp
  module Api
    class Get < BaseRequest
    end
  end
end

/lib/my_api_app/api/post.rb

module MyApiApp
  module Api
    class Post < BaseRequest
    end
  end
end

/lib/my_api_app/api/base_request.rb

module MyApiApp
  module Api
    class BaseRequest
    end
  end
end

/lib/my_api_app/api/base_response.rb

module MyApiApp
  module Api
    class BaseResponse
    end
  end
end

Searching for a solution to fix these errors I found following post which mentioned to explicitly require the path in an initializer file. For e.g.

/config/initializers/load_my_api_app_api_utility_classes.rb

require File.join(Rails.root, "lib/my_api_app/api.rb")

lib_api_dir_path = Rails.root.join("lib", "my_api_app", "api").to_s

Dir["#{lib_api_dir_path}/*.rb"].each {|file| require file }

After adding the above initializer the errors in AdminPortal app went away

NameError (uninitialized constant MyApiApp::Api):

NameError (uninitialized constant MyApiApp::Api::Get):

NameError (uninitialized > constant MyApiApp::Api::Post):

but as soon as AdminPortal app sent request to the end-point exposed by API-app I started encountering following error (mentioned previously)

NameError (uninitialized constant Api::BaseController::ApiTokenAuthentication)

So I think there is some basic thing which is missing and which is causing the errors related to auto-loading of code residing in the lib folder and which is used by the controller classes. I am really puzzled on why this is happening because I have checked /config/application.rb and in both the applications config.autoload_paths << Rails.root.join('lib') is already there.

The same code is working without any issues on staging and production envs wherein the application is running on Rails 4.2.5.1.

Also not facing these errors with the upgraded code on development environment on my local machine.

Can anybody please shed light on this and guide me towards the resolution of this weird error?

Update - Oct 19, 2016

I received following answer here to my questions above

Autoload is disabled in any environment that has eager_load enabled. You should never add lib to autoload_paths. Use eager_autoload_paths. All this information is being explained in the upgrading guide http://guides.rubyonrails.org/upgrading_ruby_on_rails.html#autoloading-is-disabled-after-booting-in-the-production-environment

I tried using the eager_load_paths approach but it started throwing new errors. As there are lot of details I have to share after using eager_load_paths, I have added them to a gist here

Hoping to receive some guidance soon.

Thanks.

Community
  • 1
  • 1
Jignesh Gohel
  • 6,236
  • 6
  • 53
  • 89

1 Answers1

1

Finally I found that there is no need neither to add anything to autoload_paths nor to eager_load_paths nor to explicitly add config.enable_dependency_loading = true to /config/environments/.rb

The reason being the utility code, which was supposed to be eager-loaded on production-kind environments i.e. production, staging etc is moved to a directory under app folder and as mentioned at https://stackoverflow.com/a/19852844/936494

Another interesting quirk is that in every rails app, all directories under app/ are
automatically in both autoload_paths and eager_load_paths, meaning that adding a directory there requires no further actions.

This way we automatically get rid of runtime errors faced like NameError (uninitialized constant MyNamespace::Api).

Thanks.

Community
  • 1
  • 1
Jignesh Gohel
  • 6,236
  • 6
  • 53
  • 89
  • No. Moving the utility code to `app` folder helped without needing to make any changes to `autoload_paths` or `eager_load_paths` or enabling `enable_dependency_loading` – Jignesh Gohel Jul 26 '18 at 07:00