テクノロジー

2018年01月09日

Railsにおけるマイグレーションとは

Aws4 request&x amz signedheaders=host&x amz signature=4af3faa538edcd7862c9635ba82cbdcbfe20db381b4930aadf271b6d843c9631

マイグレーション

今回はマイグレーションという仕組みについてです。
データのやりとりにおいてとても重要なポイントですので、ぜひ実際に手を動かしながら学んでいきましょう。

マイグレーションとは

テーブルを操作するには、SQL を実行する必要があります。
しかしRailsでは マイグレーション という仕組みのおかげで、 Ruby でテーブル操作を行うことが可能です。

マイグレーションとは マイグレーションファイル を元に テーブル操作 を行う仕組みです。
マイグレーションファイルとは、Rubyで書かれた テーブルの設計図 のことです。
テーブルの設計図とは カラムデータ型 の定義が書かれた状態のことを指します。

https://diveintocode.gyazo.com/a339f82565bd8b9414ec0d2af41f8914

マイグレーションで実現できること

ここで勘違いしないで頂きたいのは マイグレーションはテーブルを作成する機能だけではない ということです。
マイグレーションは主に以下のことが実現できます。

  • テーブル作成
  • テーブル削除
  • カラム追加
  • カラム名変更
  • カラムのデータ型変更
  • カラム削除

先ほどマイグレーションの定義として テーブルに関する操作 と述べたのは、このような理由からです。

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

マイグレーションファイルは モデルを作成した時 に一緒に作成されます。
さらに マイグレーションファイル単体 で作成することも可能です。

実際に rails g scaffold というコマンドを使ってモデルを作成してみます。

  • [x] やってみましょう!
rails g scaffold Blog title:string content:text

マイグレーションファイルは db/migrate ディレクトリに存在しています。
rails g scaffold を実行した時にすでに作成されているので見てみましょう。

  • [x] やってみましょう!

(db/migrate/YYYYMMDDhhmmss_create_blogs.rb)

class CreateBlogs < ActiveRecord::Migration
  def change
    create_table :blogs do |t| #=> この引数名(:blogs)がテーブル名になる
      t.string :title
      t.text :content
      t.timestamps  #=> この一行でcreated_atとupdated_atのカラムが定義される
    end
  end
end

次に中身がどうなっているかを見てみましょう。
create_table :blogs という記述は、これからblogsという名前でテーブルを作りますという宣言を意味します。
do-end の中にはカラムを定義してきます。
この場合、 t.string :titlet.text :contentstring型のtitleという名前のカラムtext型のcontentという名前のカラム という意味になります。
さらに t.timestamps は少し特殊で、この記述だけで レコードが作られた時間 を表す created_atカラムレコードが更新された時間 を表す updated_atカラム を作成してくれます。
両者は datetime というデータ型で定義されます。
さらにここには何も書かれていませんが、主キーである id という名前のカラムも自動で作成してくれます。

マイグレーションの実行

マイグレーションを実行するときは以下のようにコンソールに実行します。

  • [x] やってみましょう!

(コンソール)

$ rake db:migrate

マイグレーションの実行順序

マイグレーションの一番重要なポイントは 実行順序 です。
マイグレーションファイルは 時系列 で管理されています。
そのためマイグレーションファイルのファイル名は先頭が YYYYMMDDhhmmss となっているはずです。

https://diveintocode.gyazo.com/e37bbf01b50ce3f47c4afcdeb09eff0c

schema.rb

マイグレーションを実行すると schema.rb というファイルが自動で更新されます。

(db/scema.rb)

ActiveRecord::Schema.define(version: 20170302081241) do

  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"

  create_table "blogs", force: :cascade do |t|
    t.string   "title"
    t.text     "content"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

end

1行目の version: 20170302081241 のところに、実行が済んでいる最新マイグレーションファイルの日時が挿入されます。
そうすることで、マイグレーションがどこまで実行されたかが分かります。

https://diveintocode.gyazo.com/2def5f7b8293af30a3fcfca2abd97527

ちなみに schema.rb というファイルは自動で更新されるものなので 見る専門 だと認識しておいてください。
編集するとどうなるかは、興味のある方はやってみると良いと思います。

マイグレーションは一方通行

マイグレーションの実行は 一方通行 です。

https://diveintocode.gyazo.com/493b25121e90b3c0629cec9ca687cfa6

そのため一度マイグレーションを実行したら、基本的には実行済みのマイグレーションファイルを書き換えても変更されません。

なぜこのような仕組みなのか

なぜマイグレーションは時系列で管理したり、一方通行にしたりしているのでしょうか?
これは チーム開発 が関係してきます。
例えば5人でチーム開発しているときに、5人が同時にテーブル操作を行ったらDB内が混乱してしまいます。

https://diveintocode.gyazo.com/c6354d162eda65f9e9151d20ed40612a

そのため時系列で、しかも 秒単位 で管理することで DB内を混乱させない ようにしているのです。

マイグレーションをやり直す方法

テーブル操作を誤ったとき対応策は大きく3種類あります。
ここではblogsテーブルに status というカラムを新たに追加する、という設定で話を進めていきます。

  • [x] どちらか片方やってみましょう!

  • カラム追加用のマイグレーションファイルを新しく作成
  • rake db:rollback

  • [x] やらなくて良いです

  • rake db:migrate:reset

カラム追加用のマイグレーションファイルを新しく作成

まず1つ目はマイグレーションファイルを新たに作成する方法です。
一方通行というマイグレーションの仕組みを逆手に取った方法と言えるでしょう。
以下のコマンドで新しくマイグレーションファイルが作成されます。

(コンソール)

$ rails g migration add_column_to_blogs

その後マイグレーションファイルに以下を記述し、マイグレーションを実行します。

(db/migrate/YYYYMMDDhhmmss_add_column_to_blogs.rb)

class AddColumnToBlogs < ActiveRecord::Migration
  def change
    add_column :blogs, :status, :integer
  end
end

この場合 :blogsblogsテーブル:statusstatusカラム:integerintegerというデータ型 を意味します。

(コンソール)

$ rake db:migarte

rake db:rollback

rake db:rollback コマンドは、マイグレーションの実行を指定した数だけ戻してくれるコマンドです。
逆に言えば指定した数だけ、マイグレーションがリセットされるということです。
例えば以下のようなケースで、マイグレーションを1つだけ戻したいとします。

https://diveintocode.gyazo.com/8cb6362a559eeaae2f8877a49f822c69

するとschemaの日時が変更され、マイグレーションが1つ戻ります。

(コンソール)

$ rake db:rollback STEP=1

この場合 db/migrate/YYYYMMDDhhmmss_create_blogs のマイグレーションがリセットされます。

(db/migrate/YYYYMMDDhhmmss_create_blogs.rb)

class CreateBlogs < ActiveRecord::Migration
  def change
    create_table :blogs do |t|
      t.string :title
      t.text :content
      t.integer :status # 追記
      t.timestamps
    end
  end
end

その後上記のように db/migrate/YYYYMMDDhhmmss_create_blogs を編集し、マイグレーションを実行します。

(コンソール)

$ rake db:migrate

rake db:migrate:reset

rake db:migrate:reset コマンドは、DBから全てリセットしてマイグレーションを1から実行するコマンドです。
まずは以下のようにマイグレーションファイルを編集します。

  • [x] やらなくて良いです

(db/migrate/YYYYMMDDhhmmss_create_blogs.rb)

class CreateBlogs < ActiveRecord::Migration
  def change
    create_table :blogs do |t|
      t.string :title
      t.text :content
      t.integer :status # 追記
      t.timestamps
    end
  end
end

次に以下のコマンドを実行します。

  • [x] やらなくて良いです

(コンソール)

$ rake db:migrate:reset

先ほど述べたように DBから全てリセット するので、顧客のデータや個人情報を抱えた状態でこのコマンドを実行したら大変なことになるのは分かりますね。
なので使うときには気をつけなければなりません。

いかがでしたでしょうか。マイグレーションを理解することはRailsでの開発だけでなく、チーム開発にとって非常に重要なポイントになります。不明点があれば、ぜひ繰り返し学習をして身につけていきましょう。

DIVE INTO CODEのことをもっと知ってみませんか?