search
LoginSignup
10

More than 3 years have passed since last update.

posted at

updated at

Rails 5.2のマイグレーションファイルをSquasherで集約してみた

前置き

モバイルアプリのバックエンドを学習を兼ねてRailsで開発しています。「マイグレーションファイルを統合出来ないかな」と思っていたところ、こちらの書籍にてSquasherが紹介されていたので、試してみました。

まずは現状を確認する

dbディレクトリに以下のマイグレーションファイルがあります。

$ tree
.
├── migrate
│   ├── 20181129152052_create_users.rb
│   ├── 20181129152325_add_column_to_users.rb
│   ├── 20181230120205_rename_column_device_token.rb
│   ├── 20181231084154_add_index_to_user.rb
│   ├── 20181231142632_create_devices.rb
│   ├── 20181231151529_add_reference_to_users.rb
│   ├── 20181231151946_add_reference_to_devices.rb
│   ├── 20190101175529_create_rooms.rb
│   ├── 20190101182417_create_talks.rb
│   ├── 20190101183525_add_reference_to_talks.rb
│   ├── 20190101183740_add_reference_to_rooms.rb
│   ├── 20190101184243_add_reference_talk_to_users.rb
│   ├── 20190101184438_add_reference_user_to_talks.rb
│   ├── 20190102101406_create_user_room_mappings.rb
│   ├── 20190102102554_add_index_to_user_room_mappings.rb
│   ├── 20190102133103_add_column_status_to_user_rooms_mappings.rb
│   ├── 20190102134153_rename_table_user_rooms_mappings_to_residence.rb
│   ├── 20190103102845_rename_table_residence_to_residences.rb
│   ├── 20190103140215_add_reference_rooms_to_user.rb
│   ├── 20190103140817_add_reference_users_to_room.rb
│   ├── 20190103144721_rename_column_user_id_to_users.rb
│   ├── 20190109141322_rename_column_capacity_posts_par_user_to_rooms.rb
│   ├── 20190119135319_rename_column_capacity_users_to_rooms.rb
│   ├── 20190119135359_rename_column_capacity_post_per_user_to_rooms.rb
│   ├── 20190119143121_add_column_lifetime_to_rooms.rb
│   ├── 20190119143654_del_column_name_to_rooms.rb
│   ├── 20190119145901_del_reference_from_users.rb
│   └── 20190119150920_del_reference_to_rooms.rb
├── schema.rb
└── seeds.rb

インストールする

基本的には公式に沿って進めていきます。

  1. GemfileにSquasherを追記します

    Gemfile
    source 'https://rubygems.org'
    git_source(:github) { |repo| "https://github.com/#{repo}.git" }
    
    ruby '2.5.1'
    gem 'rails', '~> 5.2.2'
    gem 'mysql2', '>= 0.4.4', '< 0.6.0'
    gem 'puma', '~> 3.11'
    gem 'bootsnap', '>= 1.1.0', require: false
    gem 'config', '~> 1.7.0'
    gem 'jwt', '~> 2.1.0'
    
    group :development, :test do
      gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
      gem 'rspec-rails'
      gem 'factory_bot_rails'
    end
    
    group :development do
      gem 'listen', '>= 3.0.5', '< 3.2'
      gem 'spring'
      gem 'spring-watcher-listen', '~> 2.0.0'
      gem 'rubocop', '~> 0.60.0', require: false
    end
    
    # --- Squasherに関するGemを追加 ここから
    group :tools do
      gem 'squasher', '>= 0.6.0'
      gem 'capistrano'
      # gem 'rubocop'  当プロジェクトでは既に導入しているので除外
    end
    # --- Squasherに関するGemを追加 ここまで
    
    gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
    
  2. Gemをインストールします

    # bundle install
    Fetching gem metadata from https://rubygems.org/.........
    Fetching gem metadata from https://rubygems.org/.
    Resolving dependencies...
        :
    Fetching squasher 0.6.2
    Installing squasher 0.6.2
    Bundle complete! 16 Gemfile dependencies, 87 gems now installed.
    Bundled gems are installed into `./vendor/bundle`
    
  3. Squacherを導入します

    # bundle binstub squasher
    # bin/squasher
    Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
    Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.
    

    環境の違いからかbundle binstubs bundler --forceするよう求められました。無事に利用可能になりました:thumbsup:

    # bundle binstubs bundler --force
    # bin/squasher
    Squasher 0.6.2
    

実行する

  1. squasherコマンドの実行します

    「○○より前のマイグレーションファイルを集約する」という指示の仕方になります。今までのマイグレーションファイルを全て集約することにしますので2020年を指定します。Rails 5.2を利用しているのでmオプションの引数に5.2を指定します。

    # bin/squasher 2020 -m 5.2
    Squasher is creating a tmp database
    Dropped database 'squasher'
    Created database 'squasher'
    Squasher is applying migrations on a tmp database
    == 20181129152052 CreateUsers: migrating ======================================
    -- create_table(:users)
    -> 0.0317s
    == 20181129152052 CreateUsers: migrated (0.0319s) =============================
        :
    == 20190119150920 DelReferenceToRooms: migrating ==============================
    -- remove_reference(:rooms, :talk, {:foreign_key=>true})
    -> 0.0932s
    == 20190119150920 DelReferenceToRooms: migrated (0.0934s) =====================
    
  2. SquasherのDBの削除やクリーンの可否を選択します

    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      # デフォルト
    

実行後のマイグレーションファイルを確認する

集約されたことがわかります。

$ tree
.
├── migrate
│   └── 20190119150920_init_schema.rb
├── schema.rb
└── seeds.rb

再構築してみる

集約されたマイグレーションファイルでDBを再構築してみます。

$ bundle exec rails db:drop
Dropped database 'app_development'
Dropped database 'app_test'

$ bundle exec rails db:create
Created database 'app_development'
Created database 'app_test'

$ bundle exec rails db:migrate
== 20190119150920 InitSchema: migrating =======================================
-- create_table("devices", {:options=>"ENGINE=InnoDB DEFAULT CHARSET=utf8"})
   -> 0.0399s
    :
-- add_foreign_key("talks", "users")
   -> 0.0749s
== 20190119150920 InitSchema: migrated (0.4857s) ==============================

補足(失敗談)

Rails5.2では公式の手順をコピペしてmオプションに5.0を指定すると再構築でエラーが発生します。

# bin/squasher 2020 -m 5.0

Rails5.0ではデフォルトで作成されるidカラムはint型で、Rails5.1以降で作成されるidカラムはbigint型です。Rails5.2で作成された主キーと外部キーの関係はbigint型が前提となっているので、このようなエラーが発生します。

$ bundle exec rails db:migrate
== 20190119150920 InitSchema: migrating =======================================
-- adapter_name()
   -> 0.0000s
    :
-- add_foreign_key("devices", "users")
rails aborted!
StandardError: An error has occurred, all later migrations canceled:

Column `user_id` on table `devices` has a type of `bigint(20)`.
This does not match column `id` on `users`, which has type `int(11)`.
To resolve this issue, change the type of the `user_id` column on `devices` to be :integer. (For example `t.integer user_id`).
    :
bin/rails:4:in `<main>'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)

mオプションで継承するActiveRecord::Migrationのバージョンが変わるようですね。

mオプション 継承元
5.0 class InitSchema < ActiveRecord::Migration[5.0]
5.2 class InitSchema < ActiveRecord::Migration[5.2]

終わりに

先述の失敗談で少しハマりましたが、目的を達成することは出来ました。特にカラム名のtypoを修正するマイグレーションファイルなどは集約されスッキリしてよかったです。

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
What you can do with signing up
10