Railsのマイグレーションを使わずRidgepoleを導入してみた

みなさんは、どのようにRailsのマイグレーションファイルを運用しているでしょうか。

SQLを直接扱わなくてもデータベースのスキーマの変更をバージョン管理できるなど、マイグレーションはとてもメリットが大きいと思います。

マイグレーションを使わないという選択肢

非常にメリットの大きいマイグレーションですが、何十名もの人が、1つの巨大なモノリシックアプリケーションを開発する場合、テーブル追加やカラム変更が毎日のように行われ、互いの作業をブロックするようなコンフリクトも度々発生し、運用するのがなかなか難しくなってきます。

また、複数のプロジェクト全てで同じデータベースを参照している場合、各プロジェクトごとのマイグレーションファイルを同じ状態に揃えないとデータベースの完全な整合性が取れないという問題も生じてきます。

そのような問題への解決策として Rails のマイグレーションは使わずに、スキーマ管理用のコマンドラインツールであるRidgepoleを導入してみたいと思います。

Ridgepoleを使ってみる

環境

  • Ruby 2.3.5
  • Rails 5.1.4
  • MySQL 5.7.20

インストール

Gemfileridgepoleを追加し、bundle installします。

Gemfile
...
gem 'ridgepole'
$ bundle install

既存のデータベースからエクスポート

まずはデータベース接続情報用の設定ファイルを作成します

config.yml
adapter: mysql2
encoding: utf8mb4
database: app_development
username: root

設定ファイルを作成したら、今作成した設定ファイルを指定し、データベースから既存のスキーマ情報をエクスポートします

$ bundle exec ridgepole -c config.yml --export -o Schemafile

Schemafileが出力されたのが確認できたと思います。

Schemafile
# -*- mode: ruby -*-
# vi: set ft=ruby :

# ...略

新規テーブルを作成する

Schemafileに追記し、新規テーブルとしてbooksテーブルを作成してみたいと思います。

Schemafile
create_table "books", force: :cascade, options: "ENGINE=InnoDB" do |t|
  t.string "title",          null: false
  t.string "isbn",           null: false
  t.datetime "published_at", null: false
  t.datetime "created_at",   null: false
  t.datetime "updated_at",   null: false
  t.index ["isbn"], name: "isbn", unique: true, using: :btree
  t.index ["published_at"], name: "published_at", using: :btree
end

title, isbn, published_atカラムを持ち、isbnはユニークインデックス、published_atにはインデックスが貼られているテーブルです。

これを反映しますが、RidgepoleにはオプションでDryRunもあるので、まずは問題なく反映されそうかテストしてみます。

$ bundle exec ridgepole -c config.yml --apply --dry-run
Apply `Schemafile` (dry-run)
create_table("books", {:options=>"ENGINE=InnoDB"}) do |t|
  t.column("title", :"string", {:null=>false, :limit=>255})
  t.column("isbn", :"string", {:null=>false, :limit=>255})
  t.column("published_at", :"datetime", {:null=>false})
  t.column("created_at", :"datetime", {:null=>false})
  t.column("updated_at", :"datetime", {:null=>false})
end
add_index("books", ["isbn"], {:name=>"isbn", :unique=>true, :using=>:btree})
add_index("books", ["published_at"], {:name=>"published_at", :using=>:btree})

# CREATE TABLE `books` (
# `id` int AUTO_INCREMENT PRIMARY KEY,
# `title` varchar(255) NOT NULL,
# `isbn` varchar(255) NOT NULL,
# `published_at` datetime NOT NULL,
# `created_at` datetime NOT NULL,
# `updated_at` datetime NOT NULL)
# ENGINE=InnoDB
# CREATE UNIQUE INDEX `isbn` USING btree ON `books` (
# `isbn`)
# CREATE  INDEX `published_at` USING btree ON `books` (
# `published_at`)

DryRunすると実際に発行されるクエリも参照できるようです。

DryRunで問題なかったので、データベースに反映させたいと思います。

$ bundle exec ridgepole -c config.yml --apply
Apply `Schemafile`
-- create_table("books", {:options=>"ENGINE=InnoDB"})
   -> 0.0263s
-- add_index("books", ["isbn"], {:name=>"isbn", :unique=>true, :using=>:btree})
   -> 0.0179s
-- add_index("books", ["published_at"], {:name=>"published_at", :using=>:btree})
   -> 0.0153s

これでRidgepoleを使ってテーブルを追加することができました!

まとめ

通常のマイグレーションと変わらずRidgepoleでテーブルの追加など、スキーマの変更を行うことができました。

Railsのマイグレーションではなかなかツラくなってきたというプロジェクトは、Ridgepoleに対応するのも難しくないので、ぜひ導入を検討してみてはいかがでしょうか。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.