Plugin Migrator: migrations for your Rails plugins

Posted by collin
on Monday, May 26

Overview

My current work involves writing a handful of Rails plugins. These plugins provide additional functionality that includes ActiveRecord models that need to be persisted to the database. I originally created a migration class for one of the plugins that re-used much of the ActiveRecord logic (in fact, just overrides schema management). This worked fine, but as we started creating new plugins that needed the same functionality, we decided to pull the migration logic into a separate Rails plugin.

And hence, the PluginMigrator was born!

In order to use the PluginMigrator, your plugin must simply extend the PluginMigrator::Migrator class:

module MyPlugin
  class Migrator < PluginMigrator::Migrator

    set_schema_table_override "my_plugin_schema_info" 
    set_migration_directory(File.dirname(__FILE__) + "/../../db/migrate") 

  end
end

The set_schema_table_override method tells the plugin where the version info for your plugin should be stored. For rails apps, this schema information lives in a table named “schema_info”. You’ll need to specify a different table name for your plugin, so that your plugin migrations can be managed separately from the Rails app. Don’t worry if it doesn’t exist yet – the migration system will automatically create it.

The set_migration_directory method tells the plugin where to find the migrations. The migrations for your plugin should probably be stored in the same way as the main rails app. In your plugin root, it’s easy to just have a db/migrate structure:

To actually migrate, simply create a Rake task in your tasks directory inside of your plugin or in the main Rakefile for your plugin, depending on from where you want to run the migrate task:

namespace :myplugin do
  desc "Run the migrations for my plugin" 
  task :migrate => :environment do
    MyPlugin::Migrator.migrate(ENV['VERSION'],false)
  end
end

And then:

% rake myplugin:migrate

Typical VERSION behavior is also supported:

% rake myplugin:migrate VERSION=1

Installation

The PluginMigrator project is hosted at GitHub.

From the Terminal:

~/testapp $ cd vendor/plugins
~/testapp/vendor/plugins $ git clone git://github.com/oculardisaster/plugin_migrator.git

If you don’t have Git on your system, you can simply go to the main project page and click the download button.

Known Issues and Planned Features

  • Would like to be able to optionally exclude having the main rails app include plugin tables when writing out the schema.rb file during a Rails app migration.
  • Would like to have the plugin migrator automatically create rake tasks to migrate the plugin

A six hundred+ series

Posted by collin
on Tuesday, May 20

After much research into getting rid of lane oil and finally restoring my ball coverstock back to its near original condition I ruled the lanes today. My first 600+ series. This should help my street cred at league night tomorrow.

:D

Configuring Autotest and Growl in OS X 10.5.x

Posted by collin
on Sunday, May 11

UPDATE – Use GrowlGlue Instead

Autotest Just got a lot simpler.. For an easier time of configuring Autotest and Growl please read Configuring Autotest and Growl in OS X 10.5.x instead.



First off, if you are not running autotest then you need to start. It’s awesome and a pretty integral part of my TDD workflow. A popular combination these days is to run a combination of autotest along Growl. There are already quite a few guides out there on how to set up a development environment with autotest and Growl—why am I writing this one? It is because many of the guides out there do not work exactly right under OS X 10.5.2, making it frustrating to set up these tools. After trying a number of them, and taking what worked right and what didn’t, here is what works for me.

Setting up Autotest

Autotest is part of the ZenTest suite, which should be installed as a gem:

sudo gem install ZenTest

After you install the ZenTest gem, you should then have autotest at /usr/bin/autotest.

Setting up Growl

You can download Growl from the Growl website of course. You will want to install the Growl application normally, but then after that is complete, you will also want to install the growlnotify extra that comes with Growl.

Once you’ve installed Growl and while the DMG is still open, open up a Terminal.app window and execute the following:

cd /Volumes/Growl\ 1.1.2/Extras/growlnotify/
./install.sh 

Now you should be able to test this out by typing the following into the Terminal.ap window:

echo "Hello World" | growlnotify

If you receive a “growlnotify: command not found”, then you need to add /usr/local/bin into your PATH environment variable.

If this fails silently, that is because of an incompatibility between Growl and OS X 10.5.x that will cause dropped messages about 50% of the time. So even if you got the Growl notification, you should install the following fix for Growl.

Fixing Growl

Simply put, on OS X 10.5.x, growlnotify works about 50% of the time for me. To address this, first open up your Growl preferences (under System Preferences), click the network tab, and then make sure that the “Listen for incoming notifications” checkbox is checked. Like this:

After you set that, click back to the General tab, and then Stop Growl, and Start Growl again.

Now, the bug in Growl that I mentioned does not affect incoming network Growl notifications. So we’re going to make a wrapper for growlnotify that will forward received growl notifications to the network port that Growl listens on. Create ~/safegrowlnotify with the contents:

#!/bin/bash

# growlnotify leopard bug workaround
list_args()
{
    for p in "$@" 
    do
        if [ "${p:0:1}" == "-" ];then
            echo -n "$p " 
        else
            echo -n "\"$p\" " 
        fi
    done
}
argstr=$(list_args "${@:$?}")
echo "-H localhost $argstr" | xargs /usr/local/bin/growlnotify

And of course you will want to chmod 755 that file. To test that you have it configured, run thusly:

safegrowlnotify 'Hello World!'

You should have growl notifications coming up now:

Configuring Autotest for Growl

Now that we have everything installed, it’s time to configure Autotest. When Autotest loads up and starts the test loop, it will configure itself from ./.autotest and also ~/.autotest. It is in the latter that we’ll make our Growl modifications. This way the behavior will be shared amongst all projects that use Autotest.

Insert the the following into ~/.autotest (create if it does not already exist):

.autotest

module Autotest::Growl
  GROWLNOTIFY = "/Users/collin/safegrowlnotify" 

  def self.notify title, msg, img, pri=1, sticky="" 
    commands = ["#{GROWLNOTIFY}  --image #{img} -p #{pri} -m #{msg.inspect} #{title} #{sticky}"]
    commands.each { |c| system(c) }
  end

  Autotest.add_hook :ran_command do |at|
    results = [at.results].flatten.join("\n")
    # rpsec
    output = results.slice(/(\d+)\s+examples?,\s*(\d+)\s+failures?(,\s*(\d+)\s+pending)?/)
    if output
      if $~[2].to_i > 0
        notify "Test Results", "#{output}", "~/Library/autotest/rails_fail.png", 2
      else
        notify "Test Results", "#{output}", "~/Library/autotest/rails_ok.png" 
      end
    end
    # test::unit
    output = results.slice(/(\d+)\s+tests?,\s*(\d+)\s+assertions?,\s*(\d+)\s+failures?,\s*(\d+)\s+errors?/)
    if output
      if (($~[3].to_i > 0) or ($~[4].to_i > 0))
        notify "Test Results", "#{output}", "~/Library/autotest/rails_fail.png", 2
      else
        notify "Test Results", "#{output}", "~/Library/autotest/rails_ok.png" 
      end
    end
  end

end

(thanks to samsm for the Test::Unit modifications)

It is very important to change the value of GROWLNOTIFY to whereever you installed it previously. Also, you will want to put the following into ~/Library/autotest (create if it does not already exist). You can use whatever images you’d like, but I used these that some other kind soul before me shared in a similar blog post:

At this point, you should be all set up and ready to go. Simply running autotest should run the tests and then display the Growl messages along with an icon to boot that signifies success or failure:

Happy Autotesting!

Braves vs Padres - 5 wins in a row

Posted by collin
on Thursday, May 08

Thanks to Brett for the nice tickets to the Braves game yesterday. The seats were on the lower level, quite a bit closer than the nosebleeds I usually purchase. If we win today’s game at 1pm, we will have swept the Padres. Go Braves!