classes under lib folder are not detected in rails - ruby-on-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

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 5.2 & Bootsnap: NameError while using app/lib file

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.

Rails migration paths introduced through engine

I have a rails application that runs a rails engine by explicitly declaring it in the Gemfile. I have a script set up to install the migrations from the engine via: rake railties:install:migrations and then migrates. When I run the script, the migrations are installed but when the migrations run I get a DuplicateMigration error. I investigated this further and saw that
Rails.application.paths['db/migrate'].to_a
resulted in:
["/src/db/migrate","/bundle/bundler/gems/my_engine-w8ejw9jf/db/migrate"]
Somehow the migration path from the bundle directory is getting added to the Rails application paths. Where does this happen? Is there a way I can prevent the migration paths from my bundle directory from being included in the application paths?
Okay I did some more digging and it turns out that this is actually being done in the Engine itself. In the engine.rb file there is some logic that changes the paths that are autoloaded. The core logic was as follows:
class Engine < ::Rails::Engine
isolate_namespace MyEngine
initializer :append_migrations do |app|
unless app.root.to_s.match root.to_s
config.paths["db/migrate"].expanded.each do |expanded_path|
app.config.paths["db/migrate"] << expanded_path
end
end
end
end
This was taking the expanded paths of the migration files, and shoving them into the paths config. This is why I was seeing /bundle/bundler/gems/mycoolgem-w8ejw9jf/db/migrate in the paths config.

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.

Ruby on Rails 4.2.0: How to find the directories set for loading libraries etc

Is there a environment variable and some command-line options to check my rails application's directories that are set automatically or configured somewhere so that rails know where to load libraries etc.?
As a compare, ruby has a command line option (-I):
ruby -I path:another/path:/usr/lib rubyfile.rb arg1 arg2
such that users can set the directories where libs can be looked up by Ruby.
Similarly, here I am asking if for rails there is a similar way to check the loading paths for Rails applications? Or if there is certain variable set somewhere?
Highlight: I am using Rails version 4.2.0. The config/application.rb sample code doesn't appear to contain config.autoload_paths, not even in comments, which used to be the one for Rails 3 and Rails 4.1.x.
And, how would the Rails application know where to look up for Gems, etc.?
Thanks!
See this file:
config/application.rb
Specifically, you add this setting:
config.autoload_paths
You can add to the autoload paths like this:
config.autoload_paths << Rails.root.join('mydir')
The config.autoload_paths accepts an array of paths from which Rails will autoload constants.
The default is all directories under ./app, such as controllers, models, etc.
The default does not autoload from the typical top-level ./lib directory. If you want to autoload from lib:
config.autoload_paths << Rails.root.join('lib')
See the Rails Guides for Configuring
Rails knows where to look for gems a variety of ways: typically your environment GEM_PATH or the bundler gem bundle exec command. For example, I personally bundle my Rails gems into ./vendor/bundle/.

Resources