Faster rake tasks in Rails

Rake tasks are awesome for project specific scripts among other things, but in rails projects they suck for short tasks that don’t depend on rails. Here’s why:

  1. You type rake my_task_that_doesnt_depend_on_the_rails_environment
  2. Rails loads (10-20 seconds)
  3. Only then does your superfast rake task run. Boring!

Looking for a solution I came across Xavier Shay’s attempt to deal with this.

His solution is to maintain a list of rails tasks which depend on Rails (like rake db:migrate) in your Rakefile, and have the Rails environment autoload when any of those tasks are called. Any tasks in lib/tasks will now run nice and fast.

This helped, but it means you have to maintain a list of all the Rails tasks you may want to use (and any rake tasks included by gems used in your app) in your Gemfile, or remember to append LOAD_RAILS=1 to your rake call to force rails to load.

Because I can’t be bothered trying to remember which of my tasks depend on rails, I modified his Rakefile to autoload the Rails environment if Rake can’t find a task (on the assumption that it’ll be hidden in Rails/gem somewhere. This has the side-benefit of loading the :environment task, that any tasks which require the Rails environment depend on, if and when needed.

If you have any thoughts I’d love to hear them, the gist is here.

#!/usr/bin/env rake
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
#Load all the tasks in lib/tasks
Dir[File.expand_path('../lib/tasks/', __FILE__) + '/*.rake'].each do |file|
load file
end
#The original rails rakefile loading
def load_rails_environment
require File.expand_path('../config/application', __FILE__)
require 'rake'
MyApp::Application.load_tasks
end
#Catch task missing and try again
class Rake::Application
private
alias_method :invoke_task_without_catch, :invoke_task
def invoke_task_with_catch(*args)
begin
invoke_task_without_catch(*args)
rescue RuntimeError => e
begin
load_rails_environment
invoke_task_without_catch(*args)
rescue Exception => e
raise(e)
end
end
end
alias_method :invoke_task, :invoke_task_with_catch
end
#Add a task to the top of the rake -T list, to explain how to get the full list
#of tasks including rails and gem tasks
if ENV['LOAD_RAILS'] == '1'
load_rails_environment
else
desc "!!! Rails and gem tasks are not listed, rerun with LOAD_RAILS=1 to reveal"
task :_README
end
view raw Rakefile hosted with ❤ by GitHub