Tuesday, February 16, 2010

Rails 3: Loading rake tasks from a gem

Several times in the last year I have wished that a gem could have rake tasks that would be loaded into a Rails app. I looked into it several times but kept running into dead ends with Rails 2. Since the Rails 3 beta came out I decided to try again, this time with much more success.

Basically you are trying to include a rake task in your rails app, the tricky part is you are trying to include the rake task from the gem it is inside of, which itself is being included in the rails app.

Gem file structure
my_plugin.gemspec
lib/my_plugin.rb
lib/my_plugin/railtie.rb
tasks/my_plugin.rake

lib/my_plugin.rb
module MyPlugin
  require 'my_plugin/railtie' if defined?(Rails)
end
This file is automatically included as part of including the gem using bundler. All we need to do in this file is require our railtie.

lib/my_plugin/railtie.rb
require 'my_plugin'
require 'rails'
module MyPlugin
  class Railtie < Rails::Railtie
    railtie_name :my_plugin

    rake_tasks do
      load "tasks/my_plugin.rake"
    end
  end
end
In this file we create a railtie class inside of our module, our new class has to be a descendant of the Rails::Railtie class. The 'rake_tasks' method is defined in the Rails::Railtie class, it takes a block that it then runs during the initialization of the rake environment in your app.


lib/tasks/my_plugin.rake
desc 'my plugins rake task'
task :do_something do
  puts "the rake task did something"
end
Just a really simple rake task.


Using your new rake task
After you have built your gem and included it in your rails app using bundler the task is integrated just like any of the default rails tasks.
$ rake -T
# ...
# rake doc:rerails    # Force a rebuild of the RDOC files
# rake do_something   # my plugins rake task
# ...

$ rake do_something
# the rake task did something

Resources
http://weblog.rubyonrails.org/2010/2/9/plugin-authors-toward-a-better-future
https://gist.github.com/af7e572c2dc973add221
{"cc_re__cc_re__cc_by_3_0_us": ["er.com/rearrange?blogID=2034294260974008111&widgetType=LinkList&widgetId=LinkList1&action=editWidget&sectionId=footer-2-1' onclick='return _WidgetManager._PopupConfig(document.getElementById(\"LinkList1\"));' target='configLinkList1' title='Edit'>\n<img alt='' height='18' src='http://img1.blogblog.com/img/icon18_wrench_allbkg.png' width='18'/>\n</a>\n</span>\n</span>\n<div class='clear'></div>\n</div>\n</div><div class='widget HTML' id='HTML3'>\n<h2 class='title'>Copying</h2>\n<div class='widget-content'>\n<a rel=\"license\" href=\"http://creativecommons.org/licenses/by/3.0/us/\"><img alt=\"Creative Commons License\" style=\"border-width:0\" src=\"http://i.creativecommons.org/l/by/3.0/us/80x15.png\" /></a><br />This <span xmlns:dc=\"http://purl.org/dc/elements/1.1/\" href=\"http://purl.org/dc/dcmitype/Text\" rel=\"dc:type\">work</span> by <a xmlns:cc=\"http://creativecommons.org/ns#\" href=\"http://nathanhumbert.com\" property=\"cc:attributionName\" rel=\"cc:attributionURL\">Nathan Humbert</a> is licensed under a <a rel=\"license\" href=\"http://creativecommons.org/licenses/by/3.0/us/\">Creativ", "tent'>\n<a rel=\"license\" href=\"http://creativecommons.org/licenses/by/3.0/us/\"><img alt=\"Creative Commons License\" style=\"border-width:0\" src=\"http://i.creativecommons.org/l/by/3.0/us/80x15.png\" /></a><br />This <span xmlns:dc=\"http://purl.org/dc/elements/1.1/\" href=\"http://purl.org/dc/dcmitype/Text\" rel=\"dc:type\">work</span> by <a xmlns:cc=\"http://creativecommons.org/ns#\" href=\"http://nathanhumbert.com\" property=\"cc:attributionName\" rel=\"cc:attributionURL\">Nathan Humbert</a> is licensed under a <a rel=\"license\" href=\"http://creativecommons.org/licenses/by/3.0/us/\">Creative Commons Attribution 3.0 United States License</a>.\n</div>\n<div class='clear'></div>\n<span class='widget-item-control'>\n<span class='item-control blog-admin'>\n<a class='quickedit' href='//www.blogger.com/rearrange?blogID=2034294260974008111&widgetType=HTML&widgetId=HTML3&action=editWidget&sectionId=footer-2-1' onclick='return _WidgetManager._PopupConfig(document.getElementById(\"HTML3\"));' target='configHTML3' title='Edit'>\n<img alt='' height='18' src='http://img1.blogblog.com/img/icon18_"]}