LoginSignup
3
4

More than 3 years have passed since last update.

なぜかid列がinteger型になっているRailsのテーブルをserial型に変更する手順

Posted at

困っていたこと

ローカル環境でrails db:migrateを実行すると、何もマイグレーションを適用していないテーブルに以下のようなdiffが発生しました。(RDBMSはPostgreSQLです)

-create_table "brands", id: :serial, force: :cascade do |t|
+create_table "brands", id: :integer, default: nil, force: :cascade do |t|

原因を探ってみると、本来serial型であるべきid列のデータ型がただのinteger型になっているのが原因でした。(以下はRubyMineが生成したDDL文で確認した結果)

-- serial型なら正しい
create table brands
(
  id serial not null
    constraint brands_pkey
      primary key,

-- integer型なのはおかしい
create table brands
(
  id integer not null
    constraint brands_pkey
      primary key,

rails dbconsole(またはraild db)で\d some_tableのようにして確認するのもありです。

serial型になっている場合(sequenceが設定されている)↓

\d brands
                                        Table "public.brands"
      Column      |            Type             |                      Modifiers                      
------------------+-----------------------------+-----------------------------------------------------
 id               | integer                     | not null default nextval('brands_id_seq'::regclass)

integer型になっている場合(sequenceが設定されていない)↓

\d brands
                         Table "public.brands"
      Column      |            Type             |       Modifiers       
------------------+-----------------------------+-----------------------
 id               | integer                     | not null

なぜinteger型になっていたのかは僕もよくわかりません。
が、integer型のままでは困るので以下の手順で修正しました。

修正手順

1. 本当にserial型で正しいか確認する

念のため本番環境のデータ型を確認するなどして、本当にそのテーブルのid列がserial型でいいのかどうか確認してください。
(本番環境もinteger型だったりしたら、そっちが正になってしまいます)

2. DBのバックアップを取る

作業に失敗したときにそなえてDBのバックアップ(ダンプ)を取っておきます。

$ pg_dump your_app_development > your_app.dump

作業に失敗したときは以下のコマンドでリストアします。

$ psql -h localhost -d your_app_development < your_app.dump

3. 「次のid値」を確認する

rails dbconsoleで対象テーブルの「次のid値」を確認します。

SELECT MAX(id)+1 FROM brands;
 ?column? 
----------
        7
(1 row)

4. sequenceを設定する(=serial型に変更する)

そのまま続けて対象テーブルのid列にsequenceを設定し、dbconsoleを終了します。

-- 7は上で取得した「次のid値」
CREATE SEQUENCE brands_id_seq MINVALUE 7;
ALTER TABLE brands ALTER id SET DEFAULT nextval('brands_id_seq');
ALTER SEQUENCE brands_id_seq OWNED BY brands.id;

-- dbconsole(psql)を終了
\q

5. 動作確認

rails db:migrateを実行し、schema.rbが変更されなければ修正完了です。

もしrails db:migrate実行後にまだ以下のようなdiffが発生するようであれば、serial型に変更できていません。

-create_table "brands", id: :serial, force: :cascade do |t|
+create_table "brands", id: :integer, default: nil, force: :cascade do |t|

念のため、Rails上から対象のモデルを新しく作成したあとに正しいidが設定されていることを確認します。

# sandboxモードでrails consoleを起動
$ rails c --sandbox
> brand = Brands.new(...)
> brand.save!
> brand.id #=> 7が返ってくればOK

参考文献

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4