27

My simple rake task, stored in lib/tasks/items_spider.rake runs just fine in development. All it does is call spider! on the Item model.

namespace :items do
  desc "Spider the web for data, hoorah"
  task :spider => :environment do
    Item.spider!
  end
end

I have the :environment task as a dependency, so everything works just fine. However, when I add RAILS_ENV=production, I hit errors, both on my local server and the production server:

$ rake items:spider RAILS_ENV=production --trace
(in /home/matchu/Websites/my-rails-app)
** Invoke items:spider (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute items:spider
rake aborted!
uninitialized constant Object::Item
/home/matchu/.rvm/gems/ruby-1.9.2-preview3@rails3/gems/rake-0.8.7/lib/rake.rb:2503:in `const_missing'
/home/matchu/.rvm/gems/ruby-1.9.2-preview3@rails3/gems/rspec-core-2.0.0.beta.22/lib/rspec/core/backward_compatibility.rb:20:in `const_missing'
/home/matchu/.rvm/gems/ruby-1.9.2-preview3@rails3/gems/rspec-expectations-2.0.0.beta.22/lib/rspec/expectations/backward_compatibility.rb:6:in `const_missing'
/home/matchu/Websites/openneo-impress-items/lib/tasks/items_spider.rake:4:in `block (2 levels) in <top (required)>'
/home/matchu/.rvm/gems/ruby-1.9.2-preview3@rails3/gems/rake-0.8.7/lib/rake.rb:636:in `call'
[...trace of how rake gets to my task...]

This just seems odd to me. Apparently the models have not been loaded correctly. I'm on Rails 3.0.3, though development on this app started back when Rails 3 was in beta. How can I go about debugging this issue? Thanks!

Matchu
  • 83,922
  • 18
  • 153
  • 160

4 Answers4

43

Contrary to running your application in production, a Rake task does not eager load your entire code base. You can see it in the source:

module Rails
  class Application
    module Finisher
      # ...
      initializer :eager_load! do
        if config.cache_classes && !$rails_rake_task
          ActiveSupport.run_load_hooks(:before_eager_load, self)
          eager_load!
        end
      end
      # ...
    end
  end
end

So only if $rails_rake_task is false, will the application be eager-loaded in production. And $rails_rake_task is set to true in the :environment Rake task.

The easiest workaround is to simply require the model that you need. However, if you really need all of your application to be loaded in the Rake task, it is quite simple to load it:

Rails.application.eager_load!

The reason all of this work in development is because Rails autoloads your models in development mode. This also works from within a Rake task.

Vijay Dev
  • 26,966
  • 21
  • 76
  • 96
molf
  • 73,644
  • 13
  • 135
  • 118
  • 3
    Did a bit more research, and it turns out that this is somehow related to my app being marked as threadsafe in production, which it didn't actually occur to me to mention. I'll look a bit more into how to address that exact issue. Thanks! – Matchu Dec 02 '10 at 00:20
  • `$rails_rake_task` is no longer defined in recent versions of rake or rails, but you can still manually set `$rails_rake_task = true` in your Rakefile – Edward Anderson Nov 19 '14 at 18:30
  • Rails.application.eager_load! is not working in my rake task. It says application_controller.rb not found. I followed the trace and within active_support/dependencies.rb#search_for_file autoload_paths is empty. However in my Application.rb file I explicitly add the controllers to the autoload_paths. What's happening? – TheJKFever Jul 17 '15 at 15:57
  • This solved my issue where I was getting `NameError: uninitialized constant ...` when running a rake task in the production environment only (dev worked fine). Adding `Rails.application.eager_load!` resolved the issue for me. – seymore_strongboy Dec 01 '16 at 03:50
37

In your environment/production.rb, you should add the following:

config.dependency_loading = true if $rails_rake_task

It solved the problem for me.

(Note: this should be added AFTER the config.threadsafe! call)

Mathieu Ravaux
  • 343
  • 1
  • 5
1

The same thing happens to me in Rails 6.0.3.2.

I was trying to configure the rake file task :foo do ... end. Instead it should've been task foo: :environment do ... end.

smapira
  • 87
  • 7
0

Just found another one: I was developing on windows, deploying to Heroku. The web app and rails console worked fine, but rake tasks and even direct require could not load the model. Turned out I had absentmindedly created the model file as Model.rb instead of model.rb - system dependent case sensitivity.

Justin Love
  • 4,397
  • 25
  • 36