[Rails] change_table bulk: true のリバート時にテーブル名のプレフィックス/サフィックスが正しく適用されない問題を修正

rails/rails

修正の背景

Railsのマイグレーションで change_tablebulk: true オプションを指定すると、複数のカラム操作を1つのALTER TABLE文にまとめて実行できます。しかし、このバルク操作をリバート(ロールバック)する際に、テーブル名のプレフィックスやサフィックスが正しく適用されないバグが存在していました。

この問題は #56573 で報告され、ActiveRecord::Base.table_name_prefix または table_name_suffix を設定している環境でマイグレーションをロールバックすると、テーブル名が正しく解決されず、操作が失敗する原因となっていました。

技術的な詳細

問題の原因

CommandRecorder クラスの change_table メソッドでは、バルク操作をリバートする際に以下のようなコードが使用されていました。

変更前:

@commands << [:change_table, [table_name], -> t { bulk_change_table(table_name, commands) }]

このコードでは、リバート時に元の table_name 引数をそのまま bulk_change_table に渡していました。しかし、この table_name はプレフィックス/サフィックスが適用される前の論理的なテーブル名であり、実際のデータベース上のテーブル名とは異なる可能性がありました。

修正内容

修正後は、テーブル定義オブジェクト tname プロパティを参照するように変更されました。

変更後:

@commands << [:change_table, [table_name], -> t { bulk_change_table(t.name, commands) }]

t.name は、プレフィックスやサフィックスが既に適用された実際のテーブル名を返します。これにより、リバート時にも正しいテーブル名でSQL文が生成されるようになりました。

動作確認

修正の妥当性を確認するため、テーブル名プレフィックスを使用したテストケースが追加されました。

def test_bulk_revert_with_table_name_prefix
  ActiveRecord::Base.table_name_prefix = "prefix_"
  @connection.create_table(:prefix_testings, force: true)

  migration = Class.new(ActiveRecord::Migration::Current) {
    def write(text = ""); end

    def change
      change_table :testings, bulk: true do |t|
        t.column :foo, :string
      end
    end
  }.new

  migration.migrate(:up)
  assert @connection.column_exists?(:prefix_testings, :foo)

  assert_queries_count(1) do
    migration.migrate(:down)
  end
  assert_not @connection.column_exists?(:prefix_testings, :foo)
ensure
  @connection.drop_table :prefix_testings, if_exists: true
  ActiveRecord::Base.table_name_prefix = ""
end

このテストでは以下を検証しています:

  1. table_name_prefix = "prefix_" を設定
  2. 論理名 :testings でマイグレーションを定義(実際のテーブル名は prefix_testings
  3. マイグレーションを実行してカラム追加を確認
  4. ロールバック時に1つのクエリで処理されることを確認(バルク操作)
  5. カラムが正しく削除されることを確認

影響範囲

この修正は、以下の条件をすべて満たす場合に影響します:

  • ActiveRecord::Base.table_name_prefix または table_name_suffix を使用している
  • マイグレーションで change_table bulk: true を使用している
  • マイグレーションをロールバック(rake db:rollback)する

該当する環境では、この修正によりロールバックが正しく動作するようになります。

記事メタデータ

Generated by:
Claude Sonnet 4.5 for DiffDaily

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

ガイドライン準拠 ⚠ WARNING

記事構成とDiffDaily Styleへの準拠状況

記事構成、対象読者への適合性、コードブロックの構文は完璧です。ただし、GitHubリンク記法において、PR番号のリンクが `[PR #56578]` となっており、ガイドラインで指定された `[#56578]` 形式とわずかに異なります。可読性は高いため大きな問題ではありませんが、ガイドラインへの完全な準拠を目指す場合は修正が望ましいです。

  • 記事構成(Title、Context、Technical Detail)
  • DiffDaily Styleガイド準拠
  • カスタムMarkdown活用
  • 対象読者への適合性
技術的整合性 ✓ PASS

技術的な正確性と表現の適切性

引用されているコードはDiffの内容と完全に一致しており、ファイル名も正確です。使用されている技術用語(`change_table bulk: true`, `CommandRecorder`など)は適切であり、バグの原因と修正内容(`table_name`から`t.name`への変更)に関する技術的な説明は正確かつ論理的です。

  • 技術用語の正確性
  • コード例の正確性
  • 説明の技術的正確性
PR内容との整合性 ✓ PASS

元のPR情報との一致度

記事の内容はPRの情報(タイトル、関連Issue、コード差分)と完全に一致しています。PRで言及されていない主張や根拠のない推測(ハルシネーション)は見られず、PRの内容を忠実に要約しています。PR番号やIssue番号などの固有名詞も正確です。

  • タイトル・説明の一致
  • Diff内容の正確な反映
  • 推測の排除