In the default development.rb, cache_classes is set to false. This is what allows code changes to be reflected in each new request without requiring a server-restart. By default, this will only apply to the classes with your app, not those from external libraries or gems.
Let’s say you are extending a controller from a Rails Engine from a gem to add an action:
app/controllers/application_controller.rb
require "#{Gem.loaded_specs['my_engine'].full_gem_path}/app/controllers/application_controller'
class ApplicationController
def new_action
end
end
my_engine/app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
def old_action
end
end
On the first request, everything works fine, but at the end of the request the problem begins. Rails will unload ApplicationController because the constant :ApplicationController was marked as unloadable when your app's version was autoloaded. But, Rails also remembers that the engine's file was already required in. On the second request, your app's controller will be reloaded, but the require statement will be ignored. As a result, "old_action", won't exist, and in fact, now your ApplicationController will inherit from Object and not ActionController::Base.
The simple fix is to use require_or_load, defined in activesupport/lib/active_support/dependencies.rb.
require_or_load "#{Gem.loaded_specs['my_engine'].full_gem_path}/app/controllers/application_controller'
class ApplicationController
def new_action
end
end
More information on how Rails in development mode and autoloading is included in Required or Not? by Frederick Cheung.