Reload rails initializers - ruby-on-rails

In application.rb, I have
config.autoload_paths += %W(#{config.root}/lib
So when I modify a class under lib, my code is reloaded.
However, when I tried adding config/initializers to autoload, I noticed my code doesn't get updated.
If I'm writing an extension for the string class, I have to restart rails every time I modify my code.
Please advise?

Initializers are only loaded when starting rails (and never reloaded). When tinkering in config/initializers you will have to restart rails every time.
Of course, you could make sure your code is defined in /lib so you can still make sure it works, by using your test-suite.
E.g. in lib/speaker.rb write
module Speaker
def speak
puts "Ahum, listen: #{self.to_s}"
end
end
and in your initializer you could then do something like
class String
include Speaker
end
While this will still only get loaded when starting rails, you can develop and test your module more easily.
Hope this helps.

Initializer files are loaded only once when the rails server is started. Restart the server when initialzers values are changed.
For further information see the rails initialization guides.
Auto Reloading 'lib' on change
You can auto reload lib files. Follow Link Autoload and Reload lib directory on change
In Configuring Rails Applications: config.reload_classes_only_on_change enables or disables reloading of classes only when tracked files change. By default tracks everything on autoload paths and is set to true. If config.cache_classes is true, this option is ignored.

Related

Files at a custom dir in app/ not reloading in dev environment on Rails 5.1

I have created a new dir and subdirs in my project, just like the example below:
app/
--- services/
------ comments/
--------- create_comments_service.rb
but for every modification I make in 'create_comments_service.rb' I have to restart my server (in dev environment).
Is there anything I can do to do not have to restart my server every time I modify a file inside this dir/subdirs?
I had to add the following line in config/application.rb so Rails could recognize the files in my custom dir:
Dir[Rails.root.join('app/services/**/*.rb')].each{|rb| require rb}
Sorry, I haven't enough points to make a comment, so I'll add an answer.
In Rails 5 all folders inside app are autoloaded. You can check if the needed subfolder is in the list:
bin/rails r 'puts ActiveSupport::Dependencies.autoload_paths'
If you see services/comments in the output then maybe you need to stop your rails server, run spring stop an restart the server after it.
If you don't see - try to change the added line in config/application.rb to
config.autoload_paths += Dir[Rails.root.join('app', 'services', '**/')]
And some words about helpers.I do not agree with Martin - helpers are more often used to move out view-related code.
But he is right, it is not a common practice to make a separate service for every controller action. What is in your create_comments_service.rb?
Based on your comments, you are fighting Rails conventions, and that will almost always be punishing.
If you want to keep your controllers neat, and not clutter them with verbose code, you should put that code in your Helper Methods.
Whenever you generate a controller, it will also generate a helper file. For example rails g controller static will create app/helpers/static_helper.rb Put your excess code here, and in your controller include StaticHelper and you will have all those features from your helper avaliable in your controller keeping it nice and clean.

Run arbitrary code in a Rails plugin on reload

I have built a rails plugin and it has a requirement of building some files to work correctly. A user can manually kick this off as a rake task, but for convenience in development, I would like to add the option of rerunning this build whenever they refresh their browsers.
Just to be clear, I do not want to reLOAD the plugin every refresh, nor do I want to reload any other ruby file. I would like to run some arbitrary ruby code every time Rails decides to reload it's libraries.
First solution:
You have to add:
config.autoload_paths += %W(#{config.root}/lib)
In your Application class in config/application.rb
Please refer this link https://rails.lighthouseapp.com/projects/8994/tickets/5218-rails-3-rc-does-not-autoload-from-lib
Another One:
It is more useful try it,
New file: config/initializers/reload_lib.rb
if Rails.env == "development"
lib_reloader = ActiveSupport::FileUpdateChecker.new(Dir["lib/**/*"]) do
Rails.application.reload_routes! # or do something better here
end
ActionDispatch::Callbacks.to_prepare do
lib_reloader.execute_if_updated
end
end
It's disgusting but it's a hack. There might be a better way to trigger a full reload, but this works for me. My specific use case was a Rack app mounted to a Rails route so I needed it to reload as I worked on it in development.
Basically what it does is it checks if any files in /lib have changed (modified timestamp) since last loaded and then triggers a reload if they change.
I might also mention I have this in my config/application.rb
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
Which just by default makes sure everything in my lib directory gets loaded.
I came across this solution which is a bit more to the point.
ActionDispatch::Callbacks.to_prepare do
Rails.logger.warn "Look at me I'm updating!"
end

how do I unload & load a class?

I've got a class in /lib that I'm mucking with and testing via the console. I'm making changes to the class (adding a debugger line for instance) and using reload! but the new or removed line is not reflected in the version of the code that the console is running.
Tried these:
config.cache_classes = false
reload!
config.autoload_paths += Dir["#{config.root}/lib/**/"]
config.autoload_paths += Dir["#{config.root}/lib/service_processors"]
config.autoload_paths << 'lib'
I'm running a saved script that creates an instance of the class. I tried just loading the class at the top of my script, but that seemed to cause some unintended consequences.
So, how do I completely unload a class and then reload it? I'm thinking the script will force an unload of the class, then load the class via the file name.
Not sure it that is the problem, but in your application.rb you need to add the following line:
config.autoload_paths += %W( #{config.root}/lib )
And secondly, to make sure that classes/modules are found correctly on reload, the naming has to follow Rails conventions. This means that snake-casing a module or class name should give the filename, and different namespaces (or nesting) should be in different folders.
Some examples to make this more clear :)
class SomeClass --> /lib/some_class.rb
class SomeHTTPStuff --> /lib/some_http_stuff.rb
class API::Stuff --> /lib/api/stuff.rb
HTH.
Invalid after Rails tag added
Well, to load a class:
load "lib/class.rb"
To reload:
load "lib/class.rb"
Those settings are irrelevant.

Adding lib to 'config.autoload_paths' in Rails 3 does not autoload my module

I place a file name g.rb in side Rails.root/lib folder
The file content is like this:
module Google
end
Then I add
config.autoload_paths += %W(#{config.root}/lib #{Rails.root}/app/delayed_jobs)
to my Rails.root/config/application.rb
However, when I try to invoke Google from rails console, an exception is thrown. The exception goes away only if I execute require 'google'.
Why? Shouldn't my file is autoloaded and shouldn't I access the module without any extra require statement?
Hmm, I discovered an interesting thing. In order for Rails to auto load my class, the class name should be compliant to the file name and the folder structure.
For example, if I want to have Google module autoloaded, I must placed it inside google.rb, directly under /lib (incase I specify autoload from /lib).
If I want to auto load Google::Docs, then I either place it inside google.rb or google/docs.rb
I had a similar problem with getting my module to run on Heroku. In addition to the autoload naming convention stated by Stephen C, I found out that the module code must be require'd due to a threadsafe assumption made by the Rails' production environment on Heroku (even though threadsafe was commented out in my production.rb configuration file.) As soon as I require'd the module file before calling include on the module, everything started to work.
require 'mymodule'
include Mymodule
Please take a look at this excellent article on the subject of getting Modules to load correctly in Heroku (production).
That's because the point of autoload is not to 'require' everything up front (startup penalty). Classes are loaded as they are needed/referenced. In order to do this, you need some way to know where to look for the class. Otherwise, you would have to load every file in the autoload directory in advance to see what classes are declared. It's a tradeoff, but requiring everything in advance (as marbaq suggests) is not autoloading.
You can use the autoload command as provided by Ruby, which takes two arguments, the module to load (symbolized, i.e. :Google in your case), and the second argument is the filename, which would be g.rb if lib is in your load path ($:). See the Ruby docs for autoload.
Change config.autoload_paths to config.eager_load_paths
(based on Rails issue #6850 and Force reload! from lib directory in rails 3.2 console)
I faced the same problem just now, and my "solution" (or rather workaround) was to manually require every needed file from Rails.root/lib in my application.rb.
require 'lib/message'
require 'lib/store'
require 'lib/vault/vault.rb'
require 'lib/custom_loggers'
module MyApplication
class Application < Rails::Application
My next step would be to categorize the files in module folders as you mention.
i found this solution recently
config/application.rb
module AppName
class Application < Rails::Application
# Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += Dir[Rails.root.join('app', 'models', '{**}')]
config.autoload_paths += Dir[Rails.root.join('app', 'lib', 'extensions')]
end
end
the first config call induces rails to auto-load all sub-directories of the app/models directory
so now i can have /app/models/sub_directory/model.rb auto-loaded
(handy for organising an app with a large code base)
the second config call induces rails to autoload the lib/extensions directory
hope this helps
note: i believe this is rails 3 specific

Rails - why would a model inside RAILS_ROOT/lib not be available in production mode?

I have a class located inside RAILS_ROOT/lib folder, which I use in one of my helpers, and it works great in development.
When I switch to production, the application throws a NameError (uninitialized constant SomeHelper::SomeClass), and I have to load it manually in the helper:
load "#{Rails.root}/lib/some_class.rb"
module SomeHelper
def some_method
sc = SomeClass.new
# blah
end
end
I was under the impression that everything inside RAILS_ROOT/lib/* should be available all to the app - is there anything I need to configure to make this happen in prod mode? thanks.
When you call SomeHelper::SomeClass, Rails' autoloading mechanism will try to load file at lib/some_helper/some_class.rb
Rails won't load everything in lib/*, it will only try to load files when ConstMissing occurs.
You might need to check differences between the configuration settings between development and production environment:
config/environments/production.rb and config/environments/development.rb.
During the Rails initialization routine, load_plugins() is called which loads all plugins in config.plugin_paths. You need to make sure that your folder lib/ is included, like in
config.plugin_paths = ["#{RAILS_ROOT}/lib/plugins", "#{RAILS_ROOT}/vendor/plugins"]
In addition to config.plugin_paths, you can also name the plugins that should be loaded in config.plugins. If that variable contains :all then all plugins (found) will be loaded.
(By the way: configuration settings equal to either environment should go in config/environment.rb. Any differences between enviroments are due to settings in the respective .rb files.)

Resources