Rails

【Rails】複数のマイグレーションファイルを1つにまとめることができるgem「Squasher」を使ってみた

Rails



 

今回は複数のマイグレーションファイルを1つにまとめることができるgem 「Squasher」について解説したいと思います。マイグレーションファイルが大量に溜まってしまい調べたいマイグレーションファイルを探すのが大変になってきた、みたいな状況になった場合は導入を検討しても良いかもしれません。

Squasherとは

Squasherとは、複数のマイグレーションファイルを1つのファイルに集約することができるGemになります。

プロダクトを長年運用しているとマイグレーションファイルが大量に溜まっていき、該当のマイグレーションファイルを探し出すのが大変だったり、migrate実行に時間がかかってしまうというような状況が出てきてしまいます。

このような状況で使えるのがSquasher Gemになります。

使い方

下準備

Squasherを試す用の新規アプリケーション作成し、マイグレーションファイル(モデル)を5つほど作成しておきます。

% rails new squasher-app -d mysql
% rails db:create
% rails generate model model1
% rails generate model model2
% rails generate model model3
% rails generate model model4
% rails generate model model5
tree .
  • アプリケーション名: squasher-app
  • Ruby: 3.1.2
  • Rails: 7.0.4
  • DB: MySQL

Squasherの導入

group :development do
  gem 'squasher', '>= 0.6.0'
end
% bundle install
% bundle binstub squasher

Squasherの実行

2023年以前に作成されたマイグレーションファイル(先ほど作成したマイグレーションファイル)をまとめるコマンドは以下になります。

コマンドを打ち込むと2つの質問が返ってくるので、それぞれyesとnoを打ち込みます。

% squasher 2023
Squasher's created the `squasher` database for its needs.
It might be useful to keep it if any of your deleted migrations inserts data or
you squash migrations in a few steps (look at -r option).
Keep it (yes / no)?
yes

Do you want to clean your database from the old schema migration records(yes/no)?
no

 

すると以下のように5つあったマイグレーションファイルが1つに集約されています。

squash
class InitSchema < ActiveRecord::Migration
  def up
    create_table "model1s", charset: "utf8mb4" do |t|
      t.datetime "created_at", null: false
      t.datetime "updated_at", null: false
    end
    create_table "model2s", charset: "utf8mb4" do |t|
      t.datetime "created_at", null: false
      t.datetime "updated_at", null: false
    end
    create_table "model3s", charset: "utf8mb4" do |t|
      t.datetime "created_at", null: false
      t.datetime "updated_at", null: false
    end
    create_table "model4s", charset: "utf8mb4" do |t|
      t.datetime "created_at", null: false
      t.datetime "updated_at", null: false
    end
    create_table "model5s", charset: "utf8mb4" do |t|
      t.datetime "created_at", null: false
      t.datetime "updated_at", null: false
    end
  end

  def down
    raise ActiveRecord::IrreversibleMigration, "The initial migration is not revertable"
  end
end

トラブルシューティング

Squasher couldn’t load `database.yml`. Please, make sure that it’s present and doesn’t include any ruby code.

database.ymlに環境変数を読み込むenvが記載されている場合、Squasher実行時に以下のようなエラーが出てしまいます。

Squasher couldn't load `database.yml`. Please, make sure that it's present and doesn't include any ruby code.

 

Squasher実行時は、環境変数ではなく直接値を指定するよう修正しましょう。

# 修正前
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

# 修正後
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: 5

 

また以下のような記述も弾かれてしまうため、直接記載するよう変更します。

# 修正前
development:
  <<: *default
  database: squasher_app_development

# 修正後
development:
  adapter: mysql2
  encoding: utf8mb4
  pool: 5
  username: root
  password:
  socket: /tmp/mysql.sock
  database: squasher_app_development

参考: https://github.com/jalkoby/squasher/issues/47

Squashしたマイグレーションファイルがmigrateできない

Squashしたマイグレーションファイルがmigrateできず、以下のようなエラーが出てしまう場合があります。

% rails db:migrate
rails aborted!
StandardError: Directly inheriting from ActiveRecord::Migration is not supported. Please specify the Active Record release the migration was written for:

  class InitSchema < ActiveRecord::Migration[7.0]
/app/db/migrate/20220927083240_init_schema.rb:3:in `<main>'

Caused by:
StandardError: Directly inheriting from ActiveRecord::Migration is not supported. Please specify the Active Record release the migration was written for:

  class InitSchema < ActiveRecord::Migration[7.0]
/app/db/migrate/20220927083240_init_schema.rb:3:in `<main>'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)

 

これはマイグレーションファイルにバージョンが記載されていないことが原因のため、以下のようにバージョン指定するようにしましょう。

# 修正前
class InitSchema < ActiveRecord::Migration
  def up
    create_table "model1s", charset: "utf8mb4" do |t|
      t.datetime "created_at", null: false
      t.datetime "updated_at", null: false
    end
    create_table "model2s", charset: "utf8mb4" do |t|
      t.datetime "created_at", null: false
      t.datetime "updated_at", null: false
    end
    create_table "model3s", charset: "utf8mb4" do |t|
      t.datetime "created_at", null: false
      t.datetime "updated_at", null: false
    end
    create_table "model4s", charset: "utf8mb4" do |t|
      t.datetime "created_at", null: false
      t.datetime "updated_at", null: false
    end
    create_table "model5s", charset: "utf8mb4" do |t|
      t.datetime "created_at", null: false
      t.datetime "updated_at", null: false
    end
  end

  def down
    raise ActiveRecord::IrreversibleMigration, "The initial migration is not revertable"
  end
end

# 修正後
class InitSchema < ActiveRecord::Migration[7.0]
  def up
    create_table "model1s", charset: "utf8mb4" do |t|
      t.datetime "created_at", null: false
      t.datetime "updated_at", null: false
    end
    create_table "model2s", charset: "utf8mb4" do |t|
      t.datetime "created_at", null: false
      t.datetime "updated_at", null: false
    end
    create_table "model3s", charset: "utf8mb4" do |t|
      t.datetime "created_at", null: false
      t.datetime "updated_at", null: false
    end
    create_table "model4s", charset: "utf8mb4" do |t|
      t.datetime "created_at", null: false
      t.datetime "updated_at", null: false
    end
    create_table "model5s", charset: "utf8mb4" do |t|
      t.datetime "created_at", null: false
      t.datetime "updated_at", null: false
    end
  end

  def down
    raise ActiveRecord::IrreversibleMigration, "The initial migration is not revertable"
  end
end

まとめ

  • Squasherとは、複数のマイグレーションファイルを1つのファイルに集約することができるGem
  • % squasher <集約したいマイグレーションファイルの日付先>でマイグレーションファイルを集約することができる
  • database.ymlに環境変数を読み込むenvが記載されている場合、Squasherが実行できないので注意

参考

 

今回は今回は複数のマイグレーションファイルを1つにまとめることができるgem 「Squasher」について解説しました。半年に1回のような形で定期的にマイグレーションファイルをまとめる作業を行なっても良いかもしれませんね。