RailsのデフォルトDBはSQLiteです。一方、アプリケーションを簡単にデプロイできることで人気のPaaSであるHerokuのデフォルトDBはPostgreSQLです。
Railsでは環境ごとに異なるDBを利用している場合でも、基本的に問題なく動作します。かの有名なRailsチュートリアルでも、開発環境はSQLite、本番環境(Heroku)はPostgreSQLを使って進んでいきます。*1
これまでDBの差異によって特に困ったことがなかったので、開発環境はSQLite、HerokuはPostgreSQLという構成にしていました。が、先日ついに困ったことが起きました。
migrationファイルの構文が両立できない
Railsで既存カラムのデータ型を変更する場合、一般的には以下のmigrationファイルを用意し、rails db:migrate
します。
def change change_column :users, :age, :integer end
このmigrationファイルはSQLiteでは問題なく実行できます。しかし、PostgreSQLではPG::DatatypeMismatch〜
というエラーになってしまいます。
PostgreSQLでは、以下のように書くとmigrationを実行できます。
def change change_column :users, :age, 'integer USING CAST(age AS integer)' end
しかし、これだと今度はSQLiteでエラーが起きてしまいます。つまり、SQLiteとPostgreSQLで互換性のある書き方がないということになります。
特に理由がない限り使用するDBは揃えておくべき
Rails.env.development?
やRails.env.production?
を使って環境ごとに実行するchange_column
を切り替えることはできますが、今回の事象以外にもDBの違いは少なからずあると思いますし、そもそもDBを統一しておけば発生しない問題です。
特に理由がなければ全ての環境でDBを統一すべきだと再認識しました。
幸いこの事象に遭遇したアプリケーションは制作中で非公開だったので、どちらの環境もMySQLに統一することで問題を回避しました。公開済みのアプリの場合、簡単にはDBを変更できないので、早い段階で統一するのが良さそうです!
*1:開発環境にPostgreSQLをインストールする演習があるが、難しければ飛ばして良いとなっている