Facing runtime error NameError (uninitialized constant) for modules, classes placed in lib folder after upgrading Rails to 5.0.0.1 from 4.2.5.1 - ruby-on-rails-5

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.

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.

Related

Error message: NameError at /users/sign_in undefined local variable or method `require_no_authentication' for #<SessionsController:0x########>

I'm working on a RoR app with Devise. When I came in to work today and tried to start up my local dev environment, RoR failed when I tried to go to the sign in page:
NameError at /users/sign_in
undefined local variable or method `require_no_authentication' for #<SessionsController:0x########>
It looks like the error is not being raised within the code we wrote, but instead from deep within the Devise gem. I'm guessing that somehow, my dev machine isn't configured right.
Here are some things I've tried to fix the bug:
I ran rake db:migrate and rake db:terraform.
I ran bundle install.
I ran rvm gemset empty and bundle install to reinstall all of my gems.
None of these worked.
In addition, here are a couple more strange things about this error:
None of the other devs at my workplace are having the same error, even though they're on the same codebase.
After trying to figure out the error for a while, I switched to a branch that I haven't updated since before I started getting this bug. Even though it was working before the weekend, that branch now fails with the same error.
Does anybody know anything I could do to try to fix this error? Does it sound like some part of my local configuration is incorrectly set up?
In my project, I had added a file in app/controllers called devise_controller.rb. It looked like this:
class DeviseController < ApplicationController
# Asks Devise how much time is left until the current user is
# automatically logged out, without resetting the logout timer.
def time_until_logout
raise "let's inspect here"
end
end
When I deleted this file, the bug went away.
I filed a bug report about how adding a DeviseController caused RoR/Devise to blow up on Devise's repository: https://github.com/plataformatec/devise/issues/2520

How can I run SOME initializers when doing a Rails assets:precompile?

Background
I have an app that I recently updated to Rails 3.2.1 (from Rails 3.0.x) and have refactored the JS and CSS assets to make use of the new asset pipeline. The app is hosted on Heroku with the Celadon Cedar stack.
App Config
I keep application specific configuration in a YAML file called app_config.yml and load it into a global APP_CONFIG variable using an initializer:
# config/initializers/load_app_config.rb
app_config_contents = YAML.load_file("#{Rails.root.to_s}/config/app_config.yml")
app_config_contents["default"] ||= {}
APP_CONFIG = app_config_contents["default"].merge(
app_config_contents[Rails.env] || {} ).symbolize_keys
Asset Compilation on Heroku
Heroku has support for the Rails asset pipeline built into the Cedar stack. When you push an app to Heroku it automatically calls rake assets:precompile on the server as a step in the deploy process. However it does this in a sandboxed environment without database access or normal ENV vars.
If the application is allowed to initialize normally during asset precompilation an error is thrown trying to connect to the database. This is easily solved by adding the following to the application.rb file:
# Do not load entire app when precompiling assets
config.assets.initialize_on_precompile = false
My Problem
When initialize_on_precompile = false is set, none of the initializers in config/initializers/* are run. The problem I am running into is that I need the APP_CONFIG variable to be available during asset precompilation.
How can I get load_app_config.rb to be loaded during asset compilation without initializing the entire app? Can I do something with the group parameter passed to Rails::Application.initialize! ?
Rails lets you register initializers only in certain groups, but you need to use the Railtie API:
# in config/application.rb
module AssetsInitializers
class Railtie < Rails::Railtie
initializer "assets_initializers.initialize_rails",
:group => :assets do |app|
require "#{Rails.root}/config/initializers/load_config.rb"
end
end
end
You don't need to check if AppConfig is defined since this will only run in the assets group.
And you can (and should) continue to use initialize_on_precompile = false. The load_config.rb initializer will be run when initializing the app (since it's in config/initializers) and when pre-compiling without initializing (because of the above code).
Definitely check out asset_sync on github. Or our Heroku dev centre article on Using a CDN asset Host with Rails 3.1 on Heroku.
The issues with environment variables have recently been solved by a Heroku labs plugin, that makes your application's heroku config variables accessible during compilation time. To enable this, read about the user_env_compile plugin.
Also. There is quite a big performance improvement in using asset_sync vs letting your application lazily compile assets in production or serving them precompiled directly off your app servers. However I would say that. I wrote it.
With asset_sync and S3 you can precompile assets meaning all the assets are there ready to be served on the asset host / CDN immediately
You can only require the :assets bundle in application.rb on precompile, saving memory in production
Your app servers are NEVER hit for asset requests. You can spend expensive compute time on, you know. Computing.
Best practice HTTP cache headers are all set by default
You can enable automatic gzip compression with one extra config
Here's what I came up with. In the assets that need app configuration, I place this line at the very beginning:
<% require "#{Rails.root}/config/initializers/load_config.rb" unless defined?(AppConfig) %>
... and add .erb to the file name, so that video_player.js.coffee becomes video_player.js.coffee.erb. Then I can safely use AppConfig['somekey'] afterwards.
During the asset pre-compilation, it loads app config despite the initialize_on_precompile set to false, and does it only once (which avoids constant redefinition issues).
Yes, it's a kludge, but many times nicer than embedding configs in asset files.
For Heroku I am running the Asset Sync gem to store my files on a CDN to avoid hitting Heroku for static images. It works nicely. I also have initialize on precompile false, but the Asset Sync runs it's own initializer so you could put your code in that. https://github.com/rumblelabs/asset_sync
Although your intializer is not run when the assets are precompiling, you should still find that they run as Rails boors up as normal, however, this will be on the first hit to the application rather than at the deploy step.
I'm not entirely sure what the issue you're having is, but if you follow the Rails conventions the deploy will work as expected.

"Uninitialized constant" error when using RSpec in a Rails 3.1 project

I'm trying to use RSpec to test a Rails 3.1rc4 project. I want to test the code I have in my lib/ directory. I'm getting:
/home/julas/myapp/spec/lib/operation_spec.rb:3:in `<top (required)>': uninitialized constant MyApp (NameError)
MyApp is a module (namespace) and the problem appears whenever I try to use something from this namespace, e.g. when I try to do
describe MyApp::Something do
in my test.
The test worked without any problems earlier. I load all the stuff form the lib/ to the Rails environment by adding config.autoload_paths += Dir["#{config.root}/lib/**/"] to application.rb.
I'm really clueless what causes this. Anyone experienced something similar?
Update: it seems it wasn't related with Spork. I must have missed something.
I have no idea why this worked earlier, but it seems that to test the code from the lib directory you have to require it in the spec file (it is not auto-loaded like in e.g. controllers). Source
I was already loading the code from lib/. My issue was, my test had:
require "spec_helper"
instead of
require 'rails_helper'

Rails app error after updating OS

I updated my system to opensuse 11.4 and set up Ruby 1.9.2 via RVM. I reinstalled all the gems and updated bundle all without issue.
The problem is the vague error I get when running the app:
ActionController::RoutingError (undefined method `sub' for nil:NilClass):
app/controllers/application_controller.rb:1:in `<top (required)>'
app/controllers/news_controller.rb:1:in `<top (required)>'
I don't even know where to start looking for the problem. Both files on line 1 is the class declaration. ie class NewsController < ApplicationController and class ApplicationController < ActionController::Base. Neither files have a method call to 'sub' and no other information is given.
The app worked perfectly before the upgrade (which was using Rails 3.0.5 also) so I think the issue is somewhere in Rails, except running a new application with a simple scaffold has no problems. news#index is root in the routes file, but changing root to something else does nothing.
EDIT:
resources :categories,:addresses,:calendars,:topics,:profile,:news,:account_setting
resources :boards do
member do
get :move
post :move_category
end
end
get "user/index"
get 'login/index'
get 'login/new'
post 'login/create'
post 'login/authenticate'
get 'login/forgot_password'
put 'login/reset_password'
root :to => "news#index"
No need to do all that. I think the solution was probably a lot simpler. I just got the same error. Turns out I just had a misnamed helper module:
module AssetHelper
...
end
Should've been
module AssetsHelper
...
end
I got it resolved, although I don't know what caused it.
I created a new app and copied over app, routes, db, lib, and public and the problem disappeared.

Multiple public folders, single rails installation

I have a rails application I would like to use for multiple sites, each with different designs.
I would like to change the rails installation /public directory to something else (dynamically eventually). However, I have run into a problem (bug?) changing directories...
In my application.rb file I change the paths.public path to something other than "public" (let's say "site_one"). Here is the code:
puts paths.public.paths
paths.public = "site_one"
puts paths.public.paths
The two "puts" commands are for debugging. Now run "rails s" and you will see:
/home/macklin/app/public
/home/macklin/app/site_one
This verifies the path is changed correctly. However, shortly afterward, rails throws the following error (let me know if you need the full trace):
Exiting
/usr/lib/ruby/gems/1.8/gems/railties-3.0.3/lib/rails/paths.rb:16:in `method_missing': undefined method `javascripts' for #<Rails::Paths::Path:0x7f422bd76f58> (NoMethodError) from /usr/lib/ruby/gems/1.8/gems/actionpack-3.0.3/lib/action_controller/railtie.rb:47
My guess is it cannot find the javascripts directory even though it is clearly sitting in the "site_one" folder.
Does anyone know why I am getting this?
I know this question is pretty old, but I think I found an answer for this in Rails 4.2.
You just simply have to put this line in your config/application.rb:
middleware.use ::ActionDispatch::Static, "#{Rails.root}/another_public_folder_name", index: 'index', headers: config.static_cache_control
This makes all files in /another_public_folder_name to be served by Rails.
This is the way Rails use to setup the standard /public folder. I found it checking the sources:
https://github.com/rails/rails/blob/52ce6ece8c8f74064bb64e0a0b1ddd83092718e1/railties/lib/rails/application/default_middleware_stack.rb#L24
Duh. Just add 2 more rules for stylesheets and javascripts (I guess they get wiped when you change the parent path)
paths.public.stylesheets = "site_one/stylesheets"
paths.public.javascripts = "site_one/javascripts"