Consider this simple rake task:
task :heavy_process => :environment do
The problem I’m seeing here is that this will work in development mode, in which autoloading kicks in when the “MyModel” constant is referenced for the first time, but will fail in production mode because of the behavior described below. This issue has been bugging me for a while. I can’t recall it being a problem with Rails 2.3.5. Not sure if this is expected behavior.
If someone is writing a rake task that needs the application to be loaded, he or she will make it depend on the “:environment” task which will boot the app in the respective environment. It will also set the
$rails_rake_task global to true. This has been around for a while.
However, since the 2.3.8 and 3.0 releases, this global prevents preloading of application classes in production (or any environment in which “cache_classes” setting is enabled). This is probably so the app boots faster; users are expected to require what they need in the rake task. Here is this logic in Rails 3:
initializer :eager_load! do
if config.cache_classes && !$rails_rake_task
Going back to our initial rake task, our initial reaction is that we should put
require my_model before trying to reference MyModel. However, if MyModel is linked to other models via associations, we also need to require all of the associated models in case the
MyModel.process method uses these associations. In the end, wherever we put the require (or
require_dependency) statements, it just feels wrong and clumsy.
We’ve also been seeing migrations fail in production mode because they reference a model to do some processing. Again, the biggest problem here is that all this works like a breeze in development, making us developers feel relaxed and secure, but then surprises us when we push to production.
It occurred to me that an easy solution might be to turn off “cache_classes” setting in production if $rails_rake_task is true. Comments on that?