Helpers don't auto refresh with every request - ruby-on-rails

I am new to Ruby on Rails and recently I noticed this happening.
All code that I write in a controller
eg. class Xyz < ApplicationController...
gets refreshed with every request. Any change I make in the code in this class is reflected in the next request without restarting the server.
But any code I write in a class that does not < from ApplicationController
or a class that is in the "helpers" directory does not get auto-refreshed.
Is this normal behaviour ? Because its a pain to restart the server every time.
I am using the following in development mode :
ruby 2.0.0
Rails 4.1.8
and thin server. (also happens with webrick)

The code changes to the helpers, controllers and models are picked up the application as we refresh the page but some times it behaves weirdly and we have to restart the server.

So , basically I had created a rails-api project..that did not have the "helpers" folder by default. I had created it myself(I forgot to mention that above) ... So basically adding this line:
config.autoload_paths += %W(#{config.root}/app)
to application.rb/development.rb(depending on your need), solves this issue.
you can add :
config.autoload_paths += Dir["#{config.root}/lib/**/"]
as well if you want to autoload everything in your "lib" directory.
Hope this helps the next person.

Related

Rails controller handling discrepancy development/production

Summary: in development, requests are routed to workouts_controller.rb but in production to workouts_controllerPrev.rb
In a Rails 5.2.3 app, I have the file workouts_controller.rb in the controllers/ folder with first line:
WorkoutsController < ApplicationController
I took a copy of workouts_controller.rb (to serve as a quick reference backup) which I renamed to workouts_controllerPrev.rb and retained in the controllers/ folder.
I then introduced some new functionality to workouts_controller.rb. I tested the new functionality locally (it worked as expected in development) and then I deployed to Heroku (v 7.42.0) (for production).
The new functionality, however didn’t work in production. After some debugging, I identified that in production, the WorkoutsController class in workouts_controllerPrev.rb was handling calls to the Workouts controller (rather than the Workouts controller defined in workouts_controller.rb (as anticipated and as happening in development).
I made a more dramatic name change to workouts_controllerPrev.rb, changing it to Xwurkouts_controllerPrev.rb, and changed the class name in this file to XWurkoutsController redeployed and it all worked fine.
What is happening here? Why would Rails function differently in this respect between the 2 environments? Is this a bug or an unsurprising consequence of a bad practice of having unused files loitering around? If a bug, where should I report it?
I am using SQLite in development, and PostGreSQL in production, but I don’t see this can be a database issue? The production webserver is Puma.
Thanks for any guidance
Daniel
The issue is that both files have the same class name in them, so the actions (methods) in whichever one is loaded last will override the actions defined in the one loaded first.
If you want to keep both files around and not have surprising results, change the class name in the old file to something else like PrevWorkoutsController.
Or, save it in a branch in Git so it doesn't clutter your current code.
To answer about why you got different results in different environments, it is because of the difference between autoloading vs. eager loading. Rails uses autoloading in development, but it eager loads everything up front in production, then turns autoloading off.
In other words, in development, Rails will reload the class from its matching file any time that file is saved. In production, it simply loads all files up front, so whichever one it loads last will win.
You can read more here.

Controlling Rails Initializer Load Order (Possible Need for new Rails Initialization Hook)

I'm building a Rails Engine which uses OmniAuth. OmniAuth needs to add some middleware to the Rails middleware stack and a suggested way to do this, according to OmniAuth, is to do it in an initializer. I've tried it, and I'm successfully able to create an initializer inside the gem, which gets loaded when the Rails app starts. Now, I'm trying to add some configuration options to my gem and I would like the gem user to be able to create another initializer to configure the gem BEFORE before the gem's initializer does it's work.
What I have discovered is any initializers inside ALL Engines are loaded first. Then the initializers inside the Rails app are loaded next. I had hoped I would be able to name the initializers in such a way that I could control the load order, but Rails app initializers still process after the gem's initializers. This makes perfect sense to me, but it leaves me with a initializer load order problem. The Rails app will go last so by the time it's given a chance to configure the gem, the gem has already done it's work.
My next thought was to use the after_initialize callback inside the engine's Railtie. In most situations this might work, but in this particular use case it doesn't help. By the time after_initialize is called, the middleware stack is frozen and can't be changed (which makes it useless for code who's only purpose is to change the middleware stack).
At this point, I only see one workaround. The Rails app will have to configure the gem inside application.rb so it configure the gem before any initializers are run.
Does anyone see something I'm missing? Is there a way for the gem to do some work IMMEDIATELY after the initializers have been processed (but before Rails starts finalizing the boot process)? If not, it seems like it would be useful for Rails to have another hook that would fire as soon as the initializers are processed.
Thanks to the link suggested by #Raffael, I was able to come up with a workaround. In case anyone else runs into a similar situation, app_middleware saved the day.
I was able to register the OmniAuth middleware using app_middleware via:
class Railtie < Rails::Railtie
config.before_initialize do
setup_proc = lambda do |env|
options = {
issuer: "foo",
# Other options ...
}
env['omniauth.strategy'].options.merge!(options)
end
config.app_middleware.use OmniAuth::Builder do
provider :saml, :setup => setup_proc
end
end
end
This helped resolve the initialization order I was hitting.

Changes to .rb files that are not controllers or models don't take effect until server is restarted

I'm developing a Rails application and want to create some classes that can be called from my controller. But, whenever I make changes to those external files, I always have to restart my server. I can make changes to the controller itself and basically any other file without issue.
Notice the following two screenshots. The thing that gets me is that even the extracted source preview shows the line has been removed, and yet it behaves as though the line was there (until I restart my server).
Before change:
After change:
This is my controller
class EvaluationObject
def self.raise_error
raise "this is an error".inspect
end
And this is the class method I'm calling.
def show
EvaluationObject.raise_error
end
I already checked out "Why does Rails not refresh classes on every request (despite configuration)?" and "Rails Server needs restart every time I make changes? why?" and none of the solutions worked for me. I tend to believe I'm missing something obvious. Any thoughts?
Edit: These .rb files are in the same directory as my controllers. I've also put them in the concerns directory.

How to run a piece of code each time an ActiveRecord model is reloaded

So I have some code that rewrites paperclip file paths so that each developer on the project can have a path to their own uploads without clobbering each other, but this runs in development inside a
ActiveSupport.on_load(:after_initialize) do
loop. Which means its only loaded on initialize. The problem is that we're using the Active Reload gem (rails 3.1 so its okay), so once someone edits the a model it is reloaded and the old paperclip paths are used.
I was wondering how I could get this code to run each time a particular model was reloaded?
You could wrap it in a config.to_prepare block inside config/application.rb:
config.to_prepare do
# your code
end
This will reload upon every request in development, but only once in production.
So I tried Ryan's suggestion above, but just like I thought, it would run my code on every page load ... No Bueno.
What I wound up doing was using this piece of code that is given to you by Active Reloader, but I doubt it will work with Rails 3.2
ActiveSupport::Notifications.subscribe("active_support.dependencies.clear") do |*args|
my_code_block
end
And it worked a treat, I still had to keep the original
ActiveSupport.on_load(:after_initialize) do
block there too, so its a little ugly, but it works!
Still holding out for a cleaner solution, if one exists.

Ruby on Rails - how to reload classes?

I'm developing a Ruby on Rails app, and everytime I made changes to my class file, I need to restart the server in order for the code changes to be reflected. The code is in my controllers directory, but it's not a controller.
What change do I need to make to make the class reload automatically everytime I make a change? I've set caching to false in my environment config file, and it still doesn't work.
Any ideas?
I would probably move the code out of the controllers directory (if it isn't a controller it does not belong there) to maybe lib/controller_extensions/ and add this line to my config/application.rb (rails3) or to config/environment.rb (rails 2.3.10)
config.autoload_paths += Dir["#{config.root}/lib/controller_extensions/"]
It really depends on where the classes are originally loaded. Here is a method of reloading what you want in different environments.
Why does code need to be reloaded in Rails 3?
If its the development environment I don't think you have to change the server in order to get the changes made in the controller .Rather If there are any changes made in the Model class then you have to restart the server again.

Resources