Tech Racho エンジニアの「?」を「!」に。
  • 開発

[Rails 3] 失敗しないmigrationを書こう

migrationは、いったん他の人と共有してしまったら、容易に変更できず、基本的に追加するのみです。

うっかり環境依存なmigrationを書いてしまっても、自分や既に開発しているメンバーは気づかないことが多いのですが、
新メンバーが参加したり、本番デプロイ環境を整備したときに初めて問題に気づくことがあります。

CI環境で問題の早期発見を目指すのはもちろんですが、事前にやりがちなポイントは気をつけておきましょう。

ライブラリのmigration用メソッドに依存しない

たとえばdeviseの旧バージョンでは、t.confirmableなどのメソッドを使用していましたが、これは最新版ではDEPRECATEDになっています。

また、t.authenticatableを使用した際、バージョンによりpassword_saltが自動生成されるものとされないものがあります。

プロジェクト開始時からライブラリのバージョンを上げた場合、このようなメソッドを使っていると、エラーになったり生成されるカラムが変更されたりするので、データベースに矛盾が生じてしまいます。
特に理由が無ければ、t.string :passwordのように標準機能で記述するのがおすすめです。

モデルクラスを使わない

migration内でデータの検査や変更をする場合など、ActiveRecordのモデルを使いたくなりますが、これは危険です。
migrationは基本的にずっと残るので、仮に将来そのモデルファイルが削除された場合、rake db:migrate:resetが通らなくなってしまいます。
SQLを直接使用するか、以下のように一時的にActiveRecord::Baseを継承したクラスを作るなどの対策が必要です。

Object.const_set "User", Class.new(ActiveRecord::Base)

インデックスの長さに注意する

add_indexでリンクを張る際、長いテーブル名では、気をつけないと64文字を超えてしまうことがあります。
MySQLでは、インデックス名は基本的に64文字以下にする必要がありますが、バージョンによってはそれ以上でも通るので、気づくのが遅れると面倒なことになることがあります。

事前に、長いテーブルやカラム名の場合、インデックスには名前を付けておきましょう。

# 例: MangaRebornでは、投稿されたファンアートや翻訳をすぐに公開するかどうか、選択することができます.
# 仮に複合インデックスを張るとすると、64文字を超えます
add_index, :manga_artists,
           [:allow_publish_fan_art_immediately, 
            :allow_publish_translation_immediately], 
            :name => 'index_manga_artists_1

downをちゃんと書く

当然ですが、downをちゃんと書きましょう。

Rails 3.1以降ではchangeが使えますが、これはcreate/add系で自動処理してくれるだけなので、change_columnremove_columnの時は正しくdownを書く必要があります。

db:migrate:redoをやってからコミットすれば安心ですね。


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。