Rails 5.2 & Bootsnap: NameError while using app/lib file - ruby-on-rails

I just upgraded to Rails 5.2 and have run into the following issues in development mode, while using a class JsonWebToken from my app/lib folder in my ApplicationController.
NameError - uninitialized constant ApplicationController::JsonWebToken:
Following the directions listed here, I have the following notable things:
I'm using bootsnap that comes by default with Rails 5.2
I no longer have a require at the top of ApplicationController since files within the app folder seem to be auto-required.
In my development.rb, I have config.eager_load = false.
In my application.rb, I have the following eager and auto loading code:
autoloads lib & policy folder during production
config.eager_load_paths << Rails.root.join('lib')
config.eager_load_paths << Rails.root.join('policies')
#autoloads lib & policy folder during development
config.autoload_paths << Rails.root.join('lib')
config.autoload_paths << Rails.root.join('policies')
If I remove bootsnap, then I have to add require 'JsonWebToken' at the top of ApplicationController, and then everything works. Bootsnap didn't like that require statement at the top.
I am not sure what is the right way to be creating or using your own classes in Rails 5.2, and to set up so that they are loaded properly in both development and production. I have gone through the Rails docs, but am extremely unclear.

Related

Renaming workers per requirements of Zeitwerk (Rails 5.2.3 to 6 upgrade)

I have some Sidekiq workers that have a naming convention of like random_api_worker.rb and have the class defined as RandomAPIWorker and it has always worked up until Rails 6. In other cases, I have the classes starting off as class RandomAPIWorker although it's in a few subdirectories, such as app/workers/dir1/dir2/random_api_worker.rb
I have added config.autoloader = :classic to my application.rb file, but this seems to only do the trick if I'm running everything in development. The minute I flip the RAILS_ENV to production, then it starts complaining about worker names.
This brings me to a two questions:
Isn't the config.autoloader = :classic supposed to ignore this, or am I misunderstanding how this works?
Is there a Zeitwerk script available that could essentially upgrade classic worker names in a proper format/hierarchy?
If #1 is false, is there another way to keep my workers with their same names and not have to worry about renaming them to meet the requirements of Zeitwerk?
Here's my application.rb file:
require_relative 'boot'
require 'rails/all'
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
module Vspm
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 6.0
config.autoload = :classic
config.autoload_paths << Rails.root.join('app/workers/sampleworkers/**/')
# Settings in config/environments/* take precedence over those specified here.
# Application configuration can go into files in config/initializers
# -- all .rb files in that directory are automatically loaded after loading
# the framework and any gems in your application.
config.enable_dependency_loading = true
config.eager_load_paths += Dir["#{config.root}/lib/custom/**/"]
# Add images and subdirectories to asset pipeline
config.assets.paths << "#{Rails.root}/app/assets/images/severity_icons/"
end
Here's one error (complains about the caps in one of the class names):
ubuntu#c567d17a6700:~/myapp/app$ RAILS_ENV=production rails zeitwerk:check
Hold on, I am eager loading the application.
expected file app/services/pdf_generator.rb to define constant PdfGenerator
Here's the class name defined in that file:
# app/services/pdf_generator.rb
class PDFGenerator
After fixing this, the next error complains about the directory hierarchy not being in the worker's class name:
ubuntu#c567d17a6700:~/myapp/app$ RAILS_ENV=production rails zeitwerk:check
Hold on, I am eager loading the application.
expected file app/workers/shared/random_name_worker.rb to define constant Shared::RandomNameWorker
Here's how the class is mentioned in that file:
# app/workers/shared/random_name_worker.rb
class RandomNameWorker
Isn't the config.autoloader = :classic supposed to ignore this, or am I misunderstanding how this works?
this setting config Rails back to classic mode loader on the whole app, so of course it'll ignore structure name convenient.
you could setup autoload_paths with zeitwerk, your problem is the way you add nested workers directories to autoload_paths
# NOT THIS
config.autoload_paths << Rails.root.join('app/workers/sampleworkers/**/')
# SHOULD THIS
config.autoload_paths << Rails.root.join('app/workers/sampleworkers/')
# OR THIS (if you want to use `**`)
config.autoload_paths += Dir["#{config.root}/app/workers/**/**"]
# REPLACE
config.autoloader = :classic
# BY
config.load_defaults 6.0
Is there a Zeitwerk script available that could essentially upgrade classic worker names in a proper format/hierarchy?
i don't know whether there's a gem support that or not, i haven't seen so far, i do it manually, create module each sub directories, so your worker become something like this Api_Worker::Random
# app/worker/api_worker.rb
module ApiWorker
end
# app/worker/api_worker/random.rb
module ApiWorker
class Random
include Sidekiq::Worker
end
end
If #1 is false, is there another way to keep my workers with their same names and not have to worry about renaming them to meet the requirements of Zeitwerk?
As i said above, you could extend autoload_paths with zeitwerk
config.autoload_paths += Dir["#{config.root}/app/workers/**/**"]
and you still use the name RandomAPIWorker

Rails auto loading files from wrong location

I see lots of
LoadError: Unable to autoload constant SomeModule::MyJob expected /app/lib/some_module/my_job.rb to define it.
errors in my Rails 5.2.0 application. The part I don't understand is, why it would look inside app/lib/, since it's defined to be loaded like this in the application.rb:
config.autoload_paths << Rails.root.join('lib')
So I would expect it to load from /lib (where the module in question is located). So why is it looking inside the /app directory and how can I change it?
Change
config.autoload_paths << Rails.root.join('lib')
to
config.autoload_paths += Dir["#{Rails.root}/lib/*"]
it should work.

Rails not finding files on lib folder

Every time a controller or model tries to access a class on the /lib folder it says:
NameError (uninitialized constant 'current_controller':'class_name' did you mean 'something_else')
YES, I know the rails naming conventions and I am using it correctly. I have the code running in several other servers (Ubuntu & CentOS 6). It errors only on these 2 RedHat7.2 servers we have - same exact ruby/rails/gems on all servers. The error occurs with any library file I try to use. SELinux is disabled.
Ruby version 2.3.3; Rails version 5.1.0 (same on all servers)
Anyone have any ideas? Rails is suppose to automatically load those class files.
On rails < 5:
config/application.rb
module your_app
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
config.autoload_paths += %W(#{config.root}/lib/path)
end
end
on rails >= 5
module your_app
class Application < Rails::Application
config.eager_load_paths << "#{Rails.root}/lib/path"
end
end
If you want rails to auto load your lib you have to place it under the app folder.

Rails autoloads lib classes and modules in staging but not when pushed to production

I recently upgraded my rails app from Thin to Puma, hosted on Heroku. Everything works perfectly on staging environment, but when I deploy to production no modules or classes seem to be loaded.
The app launches and run on production but whenever one of the classes in my /lib directory is needed I get a NameError (uninitialized constant) error.
In my application.rb file this is where I load the lib files:
config.autoload_paths += Dir["#{config.root}/lib", "#{config.root}/lib/**/"]
Running Rails 3.1.1 and Ruby 2.1.1
I can't work out why they would load in staging but not production. Any help would be much appreciated!
Try Rails.root instead of config.root.
You should try add those line to application.rb:
config.eager_load_paths << Rails.root.join('lib')
config.autoload_paths << Rails.root.join('lib')
It worked for me

classes under lib folder are not detected in rails

In my project, I have written few classes under lib folder but rails is not detecting those classes in production environment. I get the uninitalized Constant error.
I use Apache in the production environment and rails script/server in the development environment.
Is anything wrong with RAILS_ROOT environment? Can anyone suggest how to overcome this problem?
I am not sure about Rails, but you achieve that in Ruby by this: (it will work in rails too, but rails must be having some elegant way)
require File.join(File.dirname(__FILE__), "lib",'your_module_name')
include your_module_name
Try this in config/application.rb (I assume you have rails3)
config.load_paths += %W( #{config.root}/lib )
Update: Rails - why would a model inside RAILS_ROOT/lib not be available in production mode?
Ensure that the name of your file matches the name of the class or module defined in it, accounting for any directories.
ie:
lib/my_new_class.rb
class MyNewClass
end
Or if you have a directory hierarchy:
lib/my_files/my_module.rb
module MyFiles
module MyModule
end
end

Resources