www.flickr.com

Today I was faced with an interesting dilemma, how does one programmatically define migrations into a plugin so you can essentially “plug-n-play”. I did a little bit of research into Rails Engines, and I wasn’t too terribly excited about the notion of having a dependency for such a small plugin, if this were something more integrated…I’d probably use it, but for this, I really only need to have these migrations run once you’ve installed the plugin, and be on my way.

So, I decided to do a little bit of research on the ActiveRecord::Migrator class to see how I could approach programmatically executing the migration outside of the standard rake task, so I could build my own custom migration rake task for my plugin.

It turns out, there are a bunch of functions you can utilize to build your own custom migration tasks for your plugin, that I wasn’t immediately aware of. Here is how I did it:

namespace :myplugin do
  desc "migrates my plugin's migration files into the database."
  task :migrate => :environment do
      ActiveRecord::Migrator.migrate(File.expand_path(File.dirname(__FILE__) + "/../db/migrate"))
      Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
  end
end

I simply saved that block of code into my plugin’s /tasks folder and named it custom_migration.rake. Next, I went to the root of my application and ran rake myplugin:migrate, and huzzah! it worked!

Nothing too amazing, and I actually based this entirely on the vanilla db:migrate function. The first line of the task essentially tells the ActiveRecord Migrator to search through my plugin’s db/migrate folder for any migration files it can find, and then brings all of them up! It would be nice if the vanilla db:migrate supported a MIGRATIONS_PATH constant so we could just use the same mechanics and build on top of them, rather than essentially re-write them just to do this.

OR better yet, wouldn’t it be nice if rails db:migrate actually scanned our plugins directory for migration files as well? That sounds like the best option to me.

Now, I am not sure if this is “the ruby way” to handle this problem, and as I stated earlier, Rails Engines is probably the way to go if you have a much larger plugin you are designing, but for me, this seemed to work just fine.

Limitations

There are some limitations to that custom task. For instance, if you were to run db:rollback, it would not be aware of the migration files that I have previously run that live within my plugin, you’d have to build another custom task to manage revoking the migrations you installed. Also, if they end up changing the way you actually migrate migrations, you might be screwed. But, alas, here is hoping for that MIGRATIONS_PATH constant!


Comments

Name (required)

Email (required)

Website

Speak your mind