塩焼きブログ

塩焼きに関しての研究内容を公開しています

Railsでのデータベース作成と変更および既存のデータベースをRailsに移行するケースの対応について

Railsではデータベースの作成やテーブルの構築や変更をSQLではなく、マイグレーションファイルで行うことができる。一見独自のルールを学ぶ必要があり、面倒だと感じるかもしれないが、デプロイの自動化に役立つ他、アプリの配布時にも役立つ。

ここでは一般的によく使われる機能などを紹介する。

データベースの作成

config/database.ymlにデータベースの設定を行い、rake db:createをすることで設定に従ってデータベースが作成される。

rake db:create
rake db:create RAILS_ENV=production

テーブルの作成

テーブルの作成用のマイグレーションファイルを手動で作成すれば良いのだが、これはモデル作成時にも自動的に生成される。例えば下記のコマンドを実行する。

rails g model User

すると下記のマイグレーションファイルが生成される。モデル作成時に必要なカラムを設定すれば、そのカラムの作成文も自動的にマイグレーションファイルに記載されるが、インデックスの作成やデフォルト値などの細かい設定を行う場合は、モデル作成時ではなくマイグレーションファイルを直接編集する方が分かりやすい場合がある。

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|

      t.timestamps
    end
  end
end

デフォルトで作成されたマイグレーションファイルではデフォルトでid, created_at, updated_atが生成されるので、その他に必要なカラムを手作業で追加すれば良い。

例えば、ユーザー名、メールアドレスを保存するテーブルを作成する場合は、このマイグレーションファイルに下記のように追加するだけで良い。

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :name
      t.string :email
      t.timestamps
    end
  end
end

この状態ではnameemailvarchar:255で作成される。

実際の利用ではlongtext, binary, int, datetimeの作成、インデックスの作成、デフォルト値、nullの設定を行いたい。これらを全て作成するサンプルが下記である。

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string   :name,          :null => false, :limit => 30
      t.string   :email
      t.string   :role,          :null => false, :default => "user"
      t.text     :profile,       :null => false, :limit => 4294967295
      t.binary   :profile_image, :null => false, :limit => 4294967295
      t.integer  :sign_in_count, :null => false, :default => 0
      t.datetime :last_sign_in_at
      t.timestamps
    end
    add_index :users, :name
    add_index :users, :role
  end
end

intintegerで作成される。bigintなどを使う場合はlimitを利用する。limitの値によって作成される型が変わる。下記はlimitの値によって作成される型のサンプルである。 How to create columns like "bigint" or "longtext" in Rails migrations, and what :limit means for column migrations - makandropedia

create_table 'example' do |t|
  t.integer :int                 # int (4 bytes, max 2,147,483,647)
  t.integer :int1, :limit => 1   # tinyint (1 byte, -128 to 127)
  t.integer :int2, :limit => 2   # smallint (2 bytes, max 32,767)
  t.integer :int3, :limit => 3   # mediumint (3 bytes, max 8,388,607)
  t.integer :int4, :limit => 4   # int (4 bytes)
  t.integer :int5, :limit => 5   # bigint (8 bytes, max 9,223,372,036,854,775,807)
  t.integer :int8, :limit => 8   # bigint (8 bytes)
  t.integer :int11, :limit => 11 # int (4 bytes)
end

textではデフォルトでtextが生成される。longtextを作成するためにサンプルではlimitを利用している。これもlimitの長さによって作成される型が変わる。 Rails 3 Migration with longtext - Stack Overflow

1 to 255 bytes: TINYTEXT 256 to 65535 bytes: TEXT 65536 to 16777215 bytes: MEDIUMTEXT 16777216 to 4294967295 bytes: LONGTEXT

ちなみにbinarylongblobで作成される。これもlimitの値によって変化する。

デフォルトではnullが許可されているが、nullを許可したくないフィールドではfalseを設定する。デフォルト値を設定したい場合はdefaultを利用する。インデックスはadd_indexで作成できる。

これらのルールを学ぶ必要があるが、仕組みを覚えてしまえばSQLを書いたり、DB管理アプリケーションが必要なくなり、デプロイの自動化が可能となる。

データベースにテーブルを作成する

ひと通りテーブルの設計が完了したら下記のコマンドでデータベースにテーブルの作成を実行できる。

rake db:migrate
rake db:migrate RAILS_ENV=production

テーブルへのカラム追加

既に開始したサービスのDBテーブルの拡張やカラムの修正といった作業を行いたい。通常は修正用のSQLを作成し、本番環境で実行するといった手続きが必要だが、Railsではこれもマイグレーションファイルで自動化できる。

マイグレーションファイルの作成

テーブルの作成ではモデルと同時に生成されたマイグレーションファイルを利用したが、このような変更時にはrails g migrationでファイルを手動作成する。

rails g migration users_update

下記のようなファイルが作成される。このファイルに処理を記述していく。

class UsersUpdate < ActiveRecord::Migration
  def change
  end
end

テーブルへの変更

テーブル名変更、カラム削除、カラム名変更、カラム追加、カラム修正、インデックス作成のサンプルである。分かりやすく各処理の上にコメントを書いている。

class UsersUpdate < ActiveRecord::Migration
  def change
    # テーブル名変更
    rename_table :users, :members

    # カラム削除
    remove_column :members, :profile
    remove_column :members, :profile_image

    # カラム名変更
    rename_column :members, :sign_in_count, login_count:
    rename_column :members, :last_sign_in_at, login_at:

    # カラム追加
    add_column :members, :password, :string, :null => false, :after => :name
    add_column :members, :items_count, :integer, :null => false, :default => 0, :after => :password

    # カラム修正
    change_column :members, :email, :string, :null => false
    change_column :members, :role, :string, :limit => 10

    # インデックス作成
    add_index :members, :email
  end
end

テーブル名変更用ファイル、カラム追加用ファイルと別々に作成する必要はなく、一つのマイグレーションファイルに様々な処理を書くことが可能。上から順に実行されるため、テーブル名を変更した場合などは、それ以降では新しいテーブル名を指定しよう。

テーブルの削除

drop_tableを利用する

class DropHoges < ActiveRecord::Migration
  def change
    drop_table :hoges
  end
end

データベースへ変更点を反映

rake db:migrate
rake db:migrate RAILS_ENV=production

既存のデータベースをRailsで管理する

新規プロジェクトではない、別言語、別フレームワークで管理している既存プロジェクトを、Railsに移行するケースへの対応はどうするか。

Railsにはrake db:schema:dumpというコマンドがある。これを利用すればschema.rbにデータベースの構造をdumpすることができる。dumpしたschema.rbの情報を元に先に記載したカラムの変更や削除を行うマイグレーションファイルを作成し、rake db:migrateでデータベースをRails管理下に移行することができる。

またテーブル内のデータをRails用に書き直す必要がある場合はRailsのタスク機能を利用して、マイグレーション実行後にタスクを起動してRails用にアップデートすれば良い。