Create a gist now

Instantly share code, notes, and snippets.

A better Rakefile for rails?

If you have rake tasks that don't rely on rails, it's really annoying that rails has to load before the tasks runs.

Instead this rakefile only loads rails if a rake task which depends on :environment is called.

One caveat is that rake -T won't list rails/gem tasks, hence the added warning. To show all tasks use rake -T LOAD_RAILS=1

With thanks to @xshay http://rhnh.net/2010/09/07/speeding-up-rails-rake

Any thoughts?

#!/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
@latentflip
Owner

Hmm, this still won't let you run tasks that you know are available, but that aren't in lib/tasks unless you add LOAD_RAILS=1

Which is particularly bad if your production environment expects them to be there :)

@latentflip
Owner

The latest revision monkey patches rake, so that we load rails if we can't find a task, seems a cleaner way of doing it, and avoids rake failing if you call a task that actually exists but is internal to rails/a gem.

@latentflip
Owner

My conclusion after a few days of use is that this current version is awesome.

@bppr
bppr commented May 19, 2012

I like this. I personally have a separate rspec suite for most of my application logic that exists outside of rails -- this is the best implementation of fighting Rails worming its way into your Rakefile that I've seen yet.

@smudge
smudge commented May 8, 2015

What's the point of doing this inside of the first rescue:

begin
  load_rails_environment
  invoke_task_without_catch(*args)
rescue Exception => e
  raise(e)
end

Why not just:

load_rails_environment
invoke_task_without_catch(*args)
@mockdeep

There appears to be a problem with this. If a task throws an error, rake seems to mark it as failed and won't run it again, so the invoke_.. in the rescue doesn't actually invoke the task. Still working on a solution, probably something involving reenable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment