How to reload Application Class in Ruby on Rails - ruby-on-rails

I noticed that my configuration which was parsed from a yml file is not being reloaded when I start up a console. Here is my application.rb file:
module MyApp
def self.config
Rails.application.config.yml_data['common']
end
class Application < Rails::Application
config.yml_data = YAML.load(ERB.new(File.read(Rails.root.join('config', 'platform', 'config.yml'))).result)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
end
end
I have config.cache_classes set to false. Is there a way to reload MyApp ??? The config never gets updated.

If you change things while the rails console is opened it will not automatically reload them. You have to use the command reload!
If it wasn’t what you are trying to do, please explain it with more detail.

Try adding your config file path to config.autoload_paths like its said on documentation

Related

Modules not loaded on production server

I have a problem because my code does not work on the production server. When it comes to development environment, everything is fine. It looks like he doesn't read the classes. My ruby version is 2.6.6 and rails is set as 5.2.4.4.
lib/crm/api.rb
module CRM
class API
# some code
end
end
app/services/crm/changes.rb
module CRM
class Changes
def initialize
#api = API.new
end
# some code
end
end
The main service is running as a cronjob.
config/schedule.rb
every 5.minutes do
runner('CRM::CheckChanges.new.call', output: "#{path}/log/crm_check_changes.log")
end
And run this code
app/services/crm/check_changes.rb
module CRM
class CheckChanges
def initialize
#changes = Changes.new
end
# some code
end
end
At first I got errors log like 'Uninitialized constant CRM::Changes::API' after reload background jobs I got 'Unitialized constant CRM::API'
config/application.rb
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += %W(#{config.root}/app)
Dir.glob(Rails.root.join('lib/**')).inject(config.autoload_paths){ |autoload_paths, path| autoload_paths << path }
As I mentioned before everything works fine on development environment. Does anyone have any idea what this could be about? Thanks in advance for answer.
You need to add /lib to the eager load paths as well:
config.autoload_paths << Rails.root.join('lib')
config.eager_load_paths << Rails.root.join('lib')
The default setting for production uses eager loading (all the classes are loaded at startup) instead of autoloading.
In production, however, you want consistency and thread-safety and can
live with a longer boot time. So eager_load is set to true, and then
during boot (before the app is ready to receive requests) Rails loads
all files in the eager_load_paths and then turns off auto loading (NB:
autoloading may be needed during eager loading). Not autoloading after
boot is a good thing, as autoloading can cause the app to have
thread-safety problems.
See Autoloading and Reloading Constants (Classic Mode). Also note that /app and all its subdirecties are already on the autoloading paths.

How can I add a services directory to the load path in Rails?

In my Rails project, I want to add services directory in app folder and include some service objects.
So let's say I want to add app/services/foo/test.rb which looks like:
module Services
module Foo
class Test
end
end
end
In my config/application.rb I added:
config.paths.add File.join('app', 'services'), glob: File.join('**', '*.rb')
config.autoload_paths += Dir[Rails.root.join('app', 'services', '*')]
However when I try to load the files in console it doesn't work:
⇒ rails c
Loading development environment (Rails 4.1.4)
[1] pry(main)> Services::Foo::Test
NameError: uninitialized constant Services
Any help how can I solve this issue?
After add new dir, reload spring
spring stop
First of all, the code under app folder will be loaded without any config.
I think the problem was the folder structure doesn't match with your class definition.
So this config will work:
app/services/foo/test.rb
module Foo
class Test
end
end
My clue is, for example we have app/controllers/api/v1/users_controllers.rb and the class constant will be Api::V1::UsersController, not Controllers::Api::V1::UsersController
Update
Conventionally, we usually use FooServices instead of Foo, it is clearer, for example:
app/services/foo_services/bar_parser.rb
module FooServices
class BarParser
# Do stuff
end
end
So we understand that every class inside foo_services folder is a service which related to Foo
My problem was because of Rails naming conventions, I suppose. I just renamed class to not use module Services and it worked.

Rails 4.1.1: uninitialized constant during initial Rails configuration

I'd like to add a microapp for errors to be processed (file I placed inside the lib folder).
module MyApp
class Application < Rails::Application
config.autoload_paths += %W( #{config.root}/lib )
config.exceptions_app = FooApp.new(Rails.public_path)
end
end
But Rails raises an unitialized constant (NameError) during it's initialization. Recently I found a similar post and tried every solution from there, but got no result. What actually I've tried:
Name a class and a filename according to convention (even tried to simplify to a single word - class Foo, filename lib/foo.rb).
Use config.eager_load_paths += %W( #{config.root}/lib ) rather than config.autoload_paths, same effect. :(
Create an initializer file and load a class with require: require "#{Rails.root}/lib/foo"
It doesn't work - seems initializers are performed after the initial Rails configuration.
Move the file into app/misc but it doesn't help.
Put a class inside a module with the same name, rename a class while it's still in the module - no effect.
The only working solution I found - is to require a file right inside the Rails configuration block, but... it's a freaky solution. Probably there still exists an idiomatic one?

Rails 4 lib classes not autoloading on change

I have a rails app in development mode.
When I make changes to a ruby class called 'Dummy' under lib/dummy it doesn't get automatically reloaded, until I restart the rails server.
The class lives in a file under
lib/dummy/dummy.rb
class Dummy
def test
puts "XXX #{var_that_does_not_exist.stuff} XXX"
end
end
If I run this, the controller that calls
dummy = Dummy.new
dummy.test
causes an error as the variable 'var_that_does_not_exist' doesn't exist. If I updated the code to remove that variable, and make another request it continues to fail, until I actually restart the rails server.
development.rb contains
config.cache_classes = false
config.reload_classes_only_on_change = false
config.serve_static_assets = false
application.rb contains
# Autoload lib/ folder including all subdirectories
config.autoload_paths += Dir["#{config.root}/lib/**/"]
config.autoload_paths += Dir["#{config.root}/lib/duummy/"]

Adding a directory to the load path in Rails?

As of Rails 2.3, what's the right way to add a directory to the load path so that it hooks into Rails' auto-reloading mechanisms?
The specific example I'm thinking of is I have a class that has several sub-classes using STI and I thought it would be a good idea to put them in a sub-directory rather than clutter the top-level. So I would have something like:
#app/models/widget.rb
class Widget < ActiveRecord::Base
add_to_load_path File.join(File.dirname(__FILE__), "widgets")
end
#app/models/widgets/bar_widget.rb
class BarWidget < Widget
end
#app/models/widgets/foo_widget.rb
class FooWidget < Widget
end
It's the add_to_load_path method that I'm looking for.
In the current version of Rails (3.2.8), this has been changed in the application.rb file.
The code is currently commented out as:
# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
Will need to update the autoload_paths value. Attempting to modify the the former load_paths variable causes this error.
/configuration.rb:85:in `method_missing': undefined method `load_paths' for #<Rails::Application::Configuration:0xac670b4> (NoMethodError)
for an example, for each path to add to autoload_paths config, add a line similar to the following:
config.autoload_paths += %W(#{config.root}/app/validators)
config.autoload_paths accepts an array of paths from which Rails will autoload constants. Default is all directories under app.
http://guides.rubyonrails.org/configuring.html
From commentor (hakunin) below:
If the directory is under app/, you don't need to add it anywhere, it should just work by default (definitely in 3.2.12). Rails has eager_load_paths that acts as autoload_paths in development, and eager load in production. All app/* directories are automatically added there.
For older versions of Rails:
You can do this in your environment.rb config file.
config.load_paths << "#{RAILS_ROOT}/app/widgets"
--
For Rails 3, see answers bellow
In Rails 5 you don't have to explicitly load folders from within the app directory anymore. All folders placed inside are directly available. You don't have to touch any of the config files. But it seems as if there are some issues with Spring.
The new workflow therefore is:
create a new folder and class inside the /app directory
run spring stop on the command line
check the autoload-paths with bin/rails r 'puts ActiveSupport::Dependencies.autoload_paths' on the command line. The new folder should now be listed.
run spring start on the command line
In Rails 3, you can set this in config/application.rb, where this sample is provided by default:
# Add additional load paths for your own custom dirs
# config.load_paths += %W( #{config.root}/extras )
On Rails 5 you need to add the following code to environment.rb:
# Add the widgets folder to the autoload path
Rails.application.configure do
config.autoload_paths << "#{Rails.root}/app/widgets"
end
Another update for rails 3 -- activesupport 3.0.0:
Instead of:
ActiveSupport::Dependencies.load_paths << "#{RAILS_ROOT}/app/widgets"
You may need to do this:
ActiveSupport::Dependencies.autoload_paths << "#{RAILS_ROOT}/app/widgets"
I found I needed to do this after config block-- no access to config object anymore.
This did the trick
ActiveSupport::Dependencies.load_paths << "#{RAILS_ROOT}/app/widgets"
In config/application.rb add config.autoload_paths << "#{config.root}/models/widgets".
File should look like this:
module MyApp
class Application < Rails::Application
config.autoload_paths << "#{config.root}/models/widgets"
end
end
I know this works for Rails 4 and 5. Probably others as well.
If you want to add multiple directories:
config.autoload_paths += Dir[Rails.root / "components/*/app/public"]
(this is an example for packwerk autoload)

Resources