Sometimes a migration needs to do more than add or remove a column. When you must convert existing data, migrations can get nasty because SQL is all you can use. You can never call models in a migration because your models will evolve away from your migrations and everyone will die. Seriously, don't do that. Think of the children!
Fortunately, there is a way to use ActiveRecord magic in your migrations and still get the girl. By inlining classes you decouple your migration from any future changes in your models. Here is an example:
Say you have two classes
Article has_many :vendors. Now you want to introduce a boolean flag
current to your
Vendor class, which determines whether the article is currently being procured from that vendor.
But what about the 14000 articles already in the database? You call up your client and decide on the following migration rule: The first vendor created for an article is to be flagged as "current".
While you can express that rule in pure SQL, you'd much rather use vanilla Ruby. So you write your migration like this:
class AddCurrentToVendor < ActiveRecord::Migration class Vendor < ActiveRecord::Base end class Article < ActiveRecord::Base has_many :vendors, :class_name => 'AddCurrentToVendor::Vendor', :order => 'created_at' end def self.up add_column :vendors, :current, :boolean Article.all.each do |article| article.vendors.first.andand.update_attribute(:current, true) end end def self.down remove_column :vendors, :current end end
Notice how our two classes were namespaced into the migration class, so
You can follow any response to this post through the Atom feed.