発生した問題
rename_tableでテーブル名を変更する際に、インデックス名が長すぎるというエラーが発生しました。
元々のインデックスは64文字以内になってるし、テーブル名変更するだけなのになんで?と思ったので調べてみました。
Index name 'xxx...' on table 'table_name' is too long; the limit is 64 characters
環境
- Rails 7.0.5
- MySQL 8.0
原因
rename_tableで、テーブル名の変更とともにインデックス名の変更の処理もされていたためでした。
変更後のインデックス名が64文字を超えていたためエラーが出たようです。
rename_tableの挙動
rename_tableのコードを見てみます。
def rename_table(table_name, new_name)
schema_cache.clear_data_source_cache!(table_name.to_s)
schema_cache.clear_data_source_cache!(new_name.to_s)
execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
rename_table_indexes(table_name, new_name)
end
テーブル名変更のSQL実行後に、rename_table_indexesが実行されています。
rename_table_indexesも見てみましょう。
def rename_table_indexes(table_name, new_name)
indexes(new_name).each do |index|
generated_index_name = index_name(table_name, column: index.columns)
if generated_index_name == index.name
rename_index new_name, generated_index_name, index_name(new_name, column: index.columns)
end
end
end
詳細を見ればわかりますが、generated_index_nameはRailsがインデックスをはる際にテーブル名とカラム名から自動生成するインデックスの名前です。
つまり、既存のインデックス名がRailsが自動生成したインデックス名なら、新しいテーブル名でインデックス名を生成し直しています。
要するに
新しいテーブル名が旧テーブル名より長くなったりするとそれによって変更されるインデックス名も長くなり、インデックス名の文字数上限(ここでは64文字)を超えてしまう場合に今回のエラーが出ていたようです。
回避策
インデックス名を明示的に指定して、Railsが生成するインデックス名と被らないようにしましょう。
rename_index :target_table, :old_index_name, :new_index_name
rename_table :target_table, :new_table