特定のマイグレーションが実行されるまで before_save を適用しない

Model の before_save は便利ですが、きちんと設計しないと before_save 内の条件によって過去のマイグレーションファイルに影響を及ぼすことがあります。

db/migrate/100_create_hoge.rb

class CreateHoge < ActiveRecord::Migration

  def self.up
    # テーブル作成
    create_table :unkos do |t|
      t.string("nickname", :null => true)
      t.timestamps
    end
    # レコード追加
    Unko.create :nickname => "toguro"
  end
	
  def self.down
    drop_table :unkos
  end

end

app/models/unko.rb

class Unko < ActiveRecord::Base
end

上記のようなマイグレーションファイルおよびモデル(Unko)がある前提で、

db/migrate/101_update_hoge.rb

class UpdateHoge < ActiveRecord::Migration

  def self.up
    # フィールド追加
    add_column :unkos, :smell, :string, :default=>"too good", :null=>false
  end
	
  def self.down
    remove_column :unkos, :smell
  end

end

上記のようなフィールドを追加するとともに

app/models/unko.rb

class Unko < ActiveRecord::Base

  before_save do |record|
    record.smell = "none" if record.smell == ""
  end

end

上記のような before_save を作り、頭から rake db:migrate を実行すると、その時点で存在しないフィールドが before_save によって参照されるため db/migrate/100_create_hoge.rb の Unko.create でコケるという感じです。

本来なら db/migrate/100_create_hoge.rb を修正できればいいんですが、特殊な事情でそれが出来ないという前提があり、これに関して以下のような記述をしたところ、問題なくマイグレーションを頭から実行することができました。

app/models/unko.rb

class Unko < ActiveRecord::Base

  before_save do |record|
    record.smell = "none" if record.smell == ""
  end if Unko.find_by_sql("select version from schema_info")[0].version.to_i >= 101

end

要は before_save の際にマイグレーションのバージョン( rake db:version )を参照し、指定したバージョン( 今回のケースの場合は 101 )までは before_save を適用しないというような寸法です。

色々検討した結果これぐらいしか解が見つからなかったのですが、なんかすごく間違ってるような気がしないでもないので、もし正しいやり方を知っている人が居ましたら教えて下さい。