LoginSignup
1
0

More than 3 years have passed since last update.

Rails6 のちょい足しな新機能を試す56(create_table if_not_exists編)

Posted at

はじめに

Rails 6 に追加されそうな新機能を試す第56段。 今回は、 create_table if_not_exists 編です。
Rails 6 では、 create_table:if_not_exists オプションが追加されました。

Ruby 2.6.3, Rails 6.0.0.rc1 で確認しました。Rails 6.0.0.rc1 は gem install rails --prerelease でインストールできます。

$ rails --version
Rails 6.0.0.rc1

マイグレーションファイルを作る

$ bin/rails g migration CreateUser name

マイグレーションファイルを修正する

:if_not_exists オプションを指定します。

db/migrate/20190713221959_create_user.rb
class CreateUser < ActiveRecord::Migration[6.0]
  def change
    create_table :users, if_not_exists: true do |t|
      t.string :name
    end
  end
end

データベースを作成する

データベースを作成します。

$ bin/rails db:create

psql でテーブルを作ります

先に users テーブルを psql で作成します。
ちょっと手抜きで id カラムは省略します。

app_development=# create table users ( name varchar(256) )
CREATE TABLE

テーブルができたことを確認しておきます。カラムの情報も確認します。

app_development=# \dt
                List of relations
 Schema |         Name         | Type  |  Owner
--------+----------------------+-------+----------
 public | ar_internal_metadata | table | postgres
 public | schema_migrations    | table | postgres
 public | users                | table | postgres
(3 rows)

app_development=# \d users;
                       Table "public.users"
 Column |          Type          | Collation | Nullable | Default
--------+------------------------+-----------+----------+---------
 name   | character varying(256) |           |          |

マイグレーションを実行する

マイグレーションを実行します。エラーは発生しません。

$ bin/rails db:migrate
== 20190713221959 CreateUser: migrating =======================================
-- create_table(:users, {:if_not_exists=>true})
   -> 0.0019s
== 20190713221959 CreateUser: migrated (0.0019s) ==============================

psql で users テーブルを確認すると id カラムが無いので、マイグレーションによってテーブルはできなかったことがわかります。

app_development=# \d users;
                       Table "public.users"
 Column |          Type          | Collation | Nullable | Default
--------+------------------------+-----------+----------+---------
 name   | character varying(256) |           |          |

ロールバックする

ロールバックしてみます。

$ bin/rails db:rollback
== 20190713221959 CreateUser: reverting =======================================
-- drop_table(:users, {:if_not_exists=>true})
   -> 0.0031s
== 20190713221959 CreateUser: reverted (0.0043s) ==============================

psql で確認すると users テーブルが削除されていることがわかります。

app_development=# \dt
                List of relations
 Schema |         Name         | Type  |  Owner
--------+----------------------+-------+----------
 public | ar_internal_metadata | table | postgres
 public | schema_migrations    | table | postgres
(2 rows)

マイグレーションを実行する

users テーブルが無い状態でマイグレーションしてみます。

$ bin/rails db:migrate

psql で確認するとテーブルが作られていることがわかります。

app_development=# \dt
                List of relations
 Schema |         Name         | Type  |  Owner
--------+----------------------+-------+----------
 public | ar_internal_metadata | table | postgres
 public | schema_migrations    | table | postgres
 public | users                | table | postgres
(3 rows)

カラムの情報を確認すると id カラムも存在しており、 migration によって作られたことがわかります。

app_development=# \d users;
                                 Table "public.users"
 Column |       Type        | Collation | Nullable |              Default
--------+-------------------+-----------+----------+-----------------------------------
 id     | bigint            |           | not null | nextval('users_id_seq'::regclass)
 name   | character varying |           |          |
Indexes:
    "users_pkey" PRIMARY KEY, btree (id)

テーブルを削除してからロールバックする

psql で users テーブルを削除します。

app_development=# drop table users

ロールバックするとエラーが発生します。

$ bin/rails db:rollback
== 20190713221959 CreateUser: reverting =======================================
-- drop_table(:users, {:if_not_exists=>true})
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:

PG::UndefinedTable: ERROR:  table "users" does not exist

エラーを回避するには

エラーを回避するには、

db/migrate/20190713221959_create_user.rb
class CreateUser < ActiveRecord::Migration[6.0]
  def change
    create_table :users, if_not_exists: true, if_exists: true do |t|
      t.string :name
    end
  end
end

とするか

db/migrate/20190713221959_create_user.rb
class CreateUser < ActiveRecord::Migration[6.0]
  def up
    create_table :users, if_not_exists: true do |t|
      t.string :name
    end
  end

  def down
    drop_table :users, if_exists: true
  end
end

とすれば良いようです。後者の方が直感的でわかりやすいので、個人的にはオススメです。
(というか前者は訳わからんし、将来、 ActiveRecord の動作が変わったりすると痛い目に合いそうです。)

試したソース

試したソースは以下にあります。
https://github.com/suketa/rails6_0_0rc1/tree/try056_create_table_if_not_exists

参考情報

1
0
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
1
0