マイグレーションファイルに外部ファイルのロジックを持ち込んではならない
以前railsで、『あるテーブルのレコードの配列を取ってきて、その配列の順番を数値として既存フィールドに上書きする』というのをマイグレーションで実行したことがありました。
このマイグレーション(VERSION=1 とします)でやらかしていたことが後から判ったため、自戒メモです。
【problem:1】
配列をとってくるのに、モデルのメソッドを使用してしまった
↓こんな感じです。
class Hoge < ActiveRecord::Base def self.get_objects self.find(:all, :order => "fuga") end end class UpdateHoge < ActiveRecord::Migration def self.up Hoge.get_objects.each_with_index do |hoge, idx| hoge.fuga = (idx + 1) end end end
【problem:2】
モデルのメソッドで使われているカラム名 fuga を、後のマイグレーション(VERSION=2 とします)で piyo に変更してしまった
このとき、マイグレーション以外のファイルではカラム名を一括置換しました。
私の開発環境ではマイグレーションを1つずつバージョンアップしていたため、当時は何も気づかなかったのですが・・・。
別環境でVERSION=0から一気にバージョンアップしようとしたところ、エラー発生。
一括置換の際にモデルのメソッドの中身が
def self.get_objects self.find(:all, :order => "piyo") end
と変わってしまったため、「piyoなんてカラムはありません」と怒られてしまったわけです。
とりあえずその場の対応としては、モデルに元のメソッド
def self.get_objects self.find(:all, :order => "fuga") end
を書き足して、マイグレーションは無事実行できるようになりました。
カラム名の変更もできれば避けるべき(というか、変更しなくていいよう慎重にDB設計すべき)でしたが、今回もっとも反省すべき点は、マイグレーションファイルに外部ファイルのロジックを持ち込んでしまったことでしょう。
- マイグレーションはデータベースの整合性を守らなくてはならない
- 外部ファイルのロジックは変更されてしまう恐れがある
これらを意識できていませんでした。
もし今回と同じようなことをする必要が出てきたら、ロジックをマイグレーション内に書くか、マイグレーションは作成せず script\console でモデルのメソッドを直接実行するべきですね。