2007年11月10日

Migration中にデータをあれこれ

先日の条件付きテーブル間リレーションシップの続きであります。

Migrationはこんな感じか。

class CreateComments < ActiveRecord::Migration def self.up create_table :comments do |t| t.column :book_id, :integer t.column :content_type, :integer t.column :content, :text end Comment.reset_column_information Book.find(:all, :conditions=>["comment is not null AND comment != ''"]).each do |book| cmnt = Comment.create(:book_id=>book.id, :content_type=>1, :content=>book.comment) end remove_column :books, :comment add_index :comments, [:books_id, :content_type] end def self.down add_column :books, :comment, :text Book.reset_column_information Comment.find(:all, :conditions=>["content_type=1"]).each do |cmnt| book = Book.find(cmnt.book_id) book.comment = cmnt.content book.update end drop_table :comments end end

これで、self.up 時に、books テーブルに格納されていたコメントが、新しい comments テーブルに移行できる。self.down はその逆である。

ここで少し、道草するが、最初、上記の Migration コードで正しく新スキーマに変わって安心していたのだが、そのまま開発が進んだあと self.down してみたくなってやってみると、全然動かない。まったく正しそうに見えるのに、おかしいなと散々悩んだあげく、Bookクラスの関連定義の所為だった。

つまり Book モデルの関連が開発が進んだ状態なので Comments モデルと has_one/belongs_to 関連がり、それが邪魔して動かなかったわけだ。しかし本当に self.down する際には、新しいモデルの状態でバージョンダウンが動くはずだ。上記のコードで言うと、self.downの 中で

book.comment = cmt.content

としているところで、book.comment は comments テーブルの参照として定義されているのがいけない。

原因が分ったらハッとひらめいた。Railsのモデルクラスは ActiveRecord::Base さえ継承していれば、完全な ActiveRecord として動くのであるから、Migration の定義に先立って

class Owner < ActiveRecord::Base end class Comments < ActiveRecord::Base end

と書いておくだけで、純粋にスキーマのメタ情報でのみ動くはずだ。
そしてこの方法は、ちゃんとうまくいく。


しかし、ここまでやってみて、はたと気づいたのだが、あれか。
バージョン管理システムからソースコードを先にMigrationをコミットした状態にまで戻してから、db:migrate VERSION=x すれば良いのだった。まだコミットしたくない開発中のコードがローカルにあると少し面倒だが、どう考えてもこれが自然であった…

続く…

投稿者 iwazawa : 2007年11月10日 22:55 | トラックバック
コメント
コメントする









名前、アドレスを登録しますか?