No Purpose

If I must say, it's for me.

RailsのmigrationでPostgreSQLのenumを使おうとするとschema.rbが生成できない

タイトルのとおりなのだけど、仕事でちょっとハマった話。

特定3種類の値だけを利用するフィールドを追加したくて、Railsenumは使いつつ、DB上でもenumで型定義しておけば"固い"よなと思って、そういうテーブル定義をしようとした。 このあたりは前職のMySQLのテーブル定義においてそういうカラムがよくあったので、まぁポスグレでもできるだろうという感覚で調べ始めた。

軽く調べてみると、以下のような記事(翻訳もあった)があったり、

naturaily.com

RailsGuidesにも「Active Record と PostgreSQL」のページに「1.7 列挙型(enumrated type)」の記載があった。

railsguides.jp

enumの型定義自体は create_table などのDSLの中でできず、

execute <<-SQL
  CREATE TYPE article_status AS ENUM ('draft', 'published');
SQL

と、SQLを直接実行しているが、これがよく行われているやり方なのかなと理解した。

自分もそのように書いてみて db:migratedb:rollback が問題なく実行できることを確認したのだが、あとからschema.rbに以下のようなメッセージが生成されていることに気がついた。

# Could not dump table #{TABLE名} because of following StandardError
#   Unknown type #{enum用に定義したtype名} for column #{enumを使いたかったカラム名}

というわけで、上に書いたようにRubyDSLでPostgresのenumが定義できないために、schema.rbも生成できないと理解した。

あとから気づいたが、close済のissueもあった。

github.com

schema.rb can't support a few database specific constructions. You need to change the format to sql if you want to use those features.

とのことで、schema.rbでなくstructure.sqlを利用するようにしてあげれば、こういったmigration用のDSLで表現できないTABLE定義も利用できそうだ。 もしstrucuture.sqlを生成したいのであれば、config.active_record.schema_format:ruby ではなく :sql に変更すればよい。

railsguides.jp

ただし言わずもがな、ActiveRecordの抽象をひっぺがして特定RDBMSへの依存を高めることにはなるので、プロジェクトでの利害は考えた方がよいと思う。