PostgreSQLの場合、Railsのmigrationで追加するカラムの順番を制御するのは難しい
はじめに
簡単に出来るだろうと高をくくっていたら、データベースがPostgreSQLの場合、そうでもなかったというお話です。
動作環境
# rake aboutより一部抜粋 Rails version 4.1.6 Database adapter postgresql
テーブル構造
以下のようなテーブルで、titleとtypeの間に、descriptionカラムを追加する想定です。
class CreateBooks < ActiveRecord::Migration def change create_table :books do |t| t.string :title # ↓この間にdescriptionを追加したい t.integer :type # ↑ t.timestamps end end end
調査開始
RailsAPI
まずはRailsAPIでadd_columnを検索してみます。 オプションの詳細は別ページに記載されているようなので、そこを見てみましたが、それっぽいオプションが見当たりません・・。 あら、もしかして出来ない?・・いや、そんなことはないだろうと、今度はググってみます。
ググる
Qiitaの記事がヒット。ズバリのものを発見。いつもありがとうございます。 どうやらafterオプションを指定してあげれば出来る模様です。
早速、以下のようなマイグレーションファイルを作成し、rake db:migrate
で実行!
カラムの順番を確認してみると・・あらら、一番最後に追加されているではありませんか・・。
Railsのバージョンが違う?データベースがMySQLだから?と疑問に思いつつもさらにググってみます。
# rails g migration AddDescriptionToBooks description:text # titleの後ろに追加したいので、after: :titleを指定 class AddDescriptionToBooks < ActiveRecord::Migration def change add_column :books, :description, :text, after: :title end end
さらにググる
今度はstackoverflowの記事がヒット。むむっ、PostgreSQLでは無効なオプションの様子。 Answerの記事を辿っていくと、PostgreSQLのWikiに到達しました。
MySQLでは簡単に出来ますが、PostgreSQLの場合、かなり面倒な手順を踏まないと出来ない模様です・・。 Wiki曰く、列の順番を変更するには、以下の3通りの方法があるとのこと。
- テーブル再作成
- 列を追加し、データを移動
- ビューを使用した違いの隠ぺい
それぞれの概略はこうです。
- テーブル再作成
- 求めているカラムの順番で、新しいテーブル(仮にnew_books)を作成
- new_booksにbooksのデータをinsert
- booksをdrop
- new_booksをbooksにリネーム
- ビューの参照先やインデックスを再作成
- 列を追加し、データを移動
- booksにdescriptionを追加
- booksにnew_typeを追加
- booksにnew_created_atを追加
- booksにnew_updated_atを追加
- booksのtypeを削除
- booksのcreated_atを削除
- booksのupdated_atを削除
- booksのnew_typeをtypeにリネーム
- booksのnew_created_atをcreated_atにリネーム
- booksのnew_updated_atをupdated_atにリネーム
- ビューの参照先やインデックスを再作成
- ビューを使用した違いの隠ぺい
- booksにdescriptionを追加
- booksをnew_booksにリネーム
- 古いテーブルと同じ名前のビュー(books)を作成
- 列の更新・挿入・削除を扱うルールを追加
Railsで実現するには?
ということで、add_columnメソッドでは実現できないため 代替手段として、SQLを直接実行する方法を模索します。
Rails GuidのActive Record Migrationsを読んでみると、 3.9 Using reversibleの記載を発見しました。 reversibleメソッド、upメソッドやdownメソッドを利用して、直接SQLを記載すればできそうです。
ただし、今回はそこまでカラムの順番にこだわっている訳ではなく 労力に見合うほどのリターンが返ってくるわけではないと判断したため、結局、単純に最後のカラムに追加することにしました。 よって、具体的な方法については割愛します。
まとめ
データベースがMySQLの場合は、add_columnメソッドにafterオプションを指定すれば、追加するカラムの順番を制御できます。
しかし、PostgreSQLの場合はそうはいかず、直接SQLを実行する等して、自前で頑張る必要があります。