LoginSignup
2
3

More than 1 year has passed since last update.

Rails マイグレーションでテーブル作成とデータ移行を同時に行う

Last updated at Posted at 2021-06-06

概要

本番運用中プロダクトへの機能追加対応により
1つのテーブルを2つにわける必要がありました。
当然ながら既存データの移行も考慮しないといけない。

作業手順としては
Railsマイグレーション機能で2つの新しいテーブル作成,
SQLによるデータ移行
考えられましたが、
今回はデータ移行もRailsマイグレーション機能で同時に行ってみました。

開発環境

  • Ruby 2.6.5
  • Rails 5.2.4
  • PostgreSQL 9.6

既存テーブル構成と分割後の構成

  • 既存テーブル構成
    一つのテーブルに数学スコアと英語スコアが混在
    image.png

  • 分割後の構成
    数学スコアと英語スコアを別々のテーブルに分割
    image.png

作業詳細

  • 新しいテーブル作成 -> データ移行順でマイグレーションが実行されるよう、マイグレーションファイルを作成する

1. 新しいテーブル作成マイグレーションファイル

  • 数学スコア用のRailsマイグレーション作成
class CreateResultMathScores < ActiveRecord::Migration[5.2]
  def change
    t.references :user, foreign_key: true, null: false
    t.float :score, null: false, comment: "数学スコア"
    t.timestamps
  end
end
  • 英語スコア用のRailsマイグレーション作成
class CreateResultEnglishScores < ActiveRecord::Migration[5.2]
  def change
    t.references :user, foreign_key: true, null: false
    t.float :score, null: false, comment: "英語スコア"
    t.timestamps
  end
end

2. データ移行マイグレーションファイル

  • データ移行用のマイグレーションはrails db:rollbackを考慮し def up def down で作成する
  • ActiveRecord Modelを使ったデータ移行も可能だが、このマイグレーションの責務はデータ移行なので Modelに依存しない形にしました
class DataMigrationResultScoresToResultMathScoresAndResultEnglishScores < ActiveRecord::Migration[5.2]
  def up
    ActiveRecord::Base.transaction do
      execute <<-SQL
        insert into result_math_scores
        (
          user_id,
          score
          create_at
          update_at
        )
        select
          user_id,
          math_score,
          now(),
          now()
        from
          result_scores
      SQL

      execute <<-SQL
        insert into result_english_scores
        (
          user_id,
          score
          create_at
          update_at
        )
        select
          user_id,
          english_score,
          now(),
          now()
        from
          result_scores
      SQL
    end
  end

  def down
    ActiveRecord::Base.transaction do
      execute <<-SQL
        delete from result_math_scores
      SQL

      execute <<-SQL
        delete from result_english_scores
      SQL
    end
  end
end

3. 既存テーブルの削除

既存テーブル(result_scores)のDropは
今のところ削除せず、様子見の予定。

結論

Railsマイグレーションでテーブル作成とデータ移行を一緒にやらない方がいいという
意見もあるようですが、rails db:rollback を考慮したマイグレーションであれば
問題ないかと思います。

2
3
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
2
3