April 20, 2009
This is just a quick 60 second intro to Rake. If you are doing development with Ruby on Rails, you undoubtedly use Rake on a daily basis. For example, you use
rake db:migrate to run your migrations or
rake test:units to run your unit tests. But do you know how to write your own Rake tasks? If you never have done that, you might hesitate to write a rake task instead thinking you ran just write a quick ruby script rather than take the time to figure out how to write a Rake task.
So to create a rake task, in an existing Rails app, create a file called
lib/tasks/app.rake. You can name it whatever you want as long as it ends in
.rake. I'm choosing to use
app because we are going to write some app-specific tasks. In the file, put this:
Now from the command line you can run your task with
rake hello_world. Nothing happens, but it runs. Now let's have it print hello world:
task :hello_world do puts "Hello, World!" end
Now when you run your task, it prints "Hello, World!". Let's add a description to our task to let people know what it does:
desc "Prints 'Hello, World!'" task :hello_world do puts "Hello, World!" end
Now if you run
rake -T, you will see your helloworld task in the list of tasks.
rake -T only shows tasks that have a description. You can also run `rake -D helloworld` to see the full description of the task. You should give all of your tasks that you expect users to run from the command-line a description.
Now a problem with our task is what happens if someone else wants to write a task named
hello_world? Well, we would have a namespace problem. So what we want to do is put all of our tasks into the
namespace :app do desc "Prints 'Hello, World!'" task :hello_world do puts "Hello, World!" end end
So now we can run our task as
So this is obviously not a real task. Let's say we want to know what the load path of our app looks like. Easy, we'll just do this:
namespace :app do desc "Prints load path of this app" task :load_paths do Rails.configuration.load_paths.each do |p| puts p end end end
When you try to run this rake tast, you will get this error:
rake aborted! uninitialized class variable @@configuration in Rails
The problem is that by default, a rake task doesn't load the Rails environment. It's easy to tell it to do that with this:
namespace :app do desc "Prints load path of this app" task :load_paths => :environment do Rails.configuration.load_paths.each do |p| puts p end end end
:load_path => :environment, you are saying that the load_path task depends on the environment being loaded. Or more specifically, you are saying "run the environment task before running this task". There is a task called "environment", and it loads the Rails environment. You won't see it under
rake -T, because it has no description because it is not a task you should run directly, only as a dependency of other tasks.
Now that we have the Rails environment loading, when you run the rake task, you will get the output you expect. If you make your task depend on environment, you will also be able to access your models from within your task. Now that you know the basics of Rake, you can easily get going making Rake tasks for your Rails app.