creating a custom rake task

December 20, 2009

There’s a nice Railscast introduction to rake for Rails, which goes into a number of other important details that aren’t covered in this post. Below is a little tutorial of creating a Rails rake task and getting it to run remotely on heroku.

Introduction to Rake

In lib/tasks, create a file called greet.rake


task :greet do
   puts "Hello world"
end

By naming the task .rake and putting it in this special place rails will automatically pick it up and make it available to you. You can see it listed if you type: rake -T on the command line. To run it:


rake greet

which will print “Hello world”

to run one task before another, specify a dependency like this (multiple tasks may be specified in the same file):


task :ask => :greet do
   puts "How are you?"
end

Writing a Practical Rake Task

Now for the task at hand, I’m going to create a rake task which creates a bunch of fake data for me to test with. First I’ll create a little experimental app:


rails rake_example
cd rake example
script/generate scaffold person first_name:string last_name:string
rake db:migrate
rails generate admin fake_people

Here’s the rake task (lib/tasks/fake_people.rake):


require 'faker'

namespace :admin  do
  desc "create some fake data"
  task :fake_people => :environment do
    print "How many fake people do you want?"
    num_people = $stdin.gets.to_i
    num_people.times do
      Person.create(:first_name => Faker::Name.first_name,
                    :last_name => Faker::Name.last_name)
    end
    print "#{num_people} created.n"
  end
end

Note that I’m using the faker gem (docs here) and I created a task dependency on loading the rails environment so I could access my Person model.

Now I can run


rake admin:fake_people

and it will prompt me to ask how many I want and then it will create them. Cool goodness, yes?

Running Remotely on Heroku

We’re not done yet. I want to deploy this on heroku and be able to run the task remotely. For this, there are two gotchas, first I can’t run an interactive script remotely; also I need to tell heroku that I am using the fake gem and make sure it is installed.

1) removing interactivity

Instead of an interactive script, we can set an environment variable or command line argument (thanks to a tip by Adam Wiggins).

My modified task looks like this:


require 'faker'

namespace :admin  do
  desc "create some fake data"
  task :fake_people => :environment do
    num_people = ENV['NUM_RECORDS'].to_i
    num_people.times do
      Person.create(:first_name => Faker::Name.first_name,
                    :last_name => Faker::Name.last_name)
    end
    print "#{num_people} created.n"
  end
end

which I can call locally from the command line like this:


rake admin:fake_people NUM_RECORDS=1

2) adding gem to heroku

I need to create a gems manifest, which sounds fancy, but is simply creating a .gems file at the root of my app with contents similar to what I would put in my config environment.rb to specify that my app requires a gem:


faker --version ">=0.3.1"

3) Deploy and Run

So I can deploy my app to heroku with the usual steps


git init
git add .
git commit -m "example app for rake script testing"
heroku create
git push heroku master
heroku rake db:migrate

and run the task remotely:


heroku run rake admin:fake_people NUM_RECORDS=1