LoginSignup
11
8

More than 5 years have passed since last update.

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

Posted at

みなさんは、どのように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に対応するのも難しくないので、ぜひ導入を検討してみてはいかがでしょうか。

11
8
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
11
8