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.