rake db:migrate
でテーブルを作成した時、index名が長すぎると下記のようなエラーが出ます。
Index name 'index_name' on table 'table_name' is too long; the limit is 64 characters
railsでindexが追加されるのは主にこの3つです
t.references で関連づけた場合
index: true オプションで関連づけた場合
add_index で関連づけた場合
それぞれ対処法が異なるので、今回はこちらを紹介したいと思います。
結論
t.references で関連づけたindex名を変更する場合
t.references :table_name, index: { name: 'index_name' }
index: true オプションで関連づけたindex名を変更する場合
t.integer :column_name, index: { name: 'index_name' }
add_indexで関連づけたindex名を変更する場合
add_index :table_name, :column_name, name: 'index_name'
目次
- 結論
- 環境
- migrationを実行したらエラーが出た
- Railsでindexが貼られるパターン
t.references で関連づけた場合
- index: true オプションで関連づけた場合
add_index で関連づけた場合
- まとめ
環境
作業環境
OS: MacOS
メモリ: 32GB
Dependents
Rails6
Ruby 2.6
CentOS7 on Vagrant
Mysql 5.7
migrationを実行したらエラーが出た
Railsのmigrationについては、公式ドキュメントに詳細が載っていますので
そちらを見てみてください。
既存のアプリケーションに、新しいテーブルを追加するために
migrationファイルを作成しました。
(内容は適当です)
# migrationファイル
class CreateMigrationErrorTables < ActiveRecord::Migration[6.1]
def change
create_table :migration_index_name_errors do |t|
t.integer :error_num, null: false
t.string :error_string
t.timestamps
end
create_table :migration_index_name_error_items do |t|
t.references :item, null: false
t.integer :display_order, null: false
t.timestamps
end
end
end
こちらでmigrationを実行した所、このようなエラーが発生しました。
ログの全文はこんな感じです。
# log
[vagrant@sample app]$ bundle exec rake db:migrate
== 20210426060841 CreateMigrationErrorTables: migrating ======================
-- create_table(:migration_index_name_errors)
-> 0.0128s
-- create_table(:migration_index_name_error_items)
rake aborted!
StandardError: An error has occurred, all later migrations canceled:
Index name 'index_migration_index_name_error_items_on_migration_index_name_error_id' on table 'migration_index_name_error_items' is too long; the limit is 64 characters
/home/vagrant/app/db/migrate/20210426060841_create_migration_error_tables.rb:10:in `change'
/home/vagrant/.rbenv/versions/2.7.2/bin/bundle:23:in `load'
/home/vagrant/.rbenv/versions/2.7.2/bin/bundle:23:in `<main>'
Caused by:
ArgumentError: Index name 'index_migration_index_name_error_items_on_migration_index_name_error_id' on table 'migration_index_name_error_items' is too long; the limit is 64 characters
/home/vagrant/app/db/migrate/20210426060841_create_migration_error_tables.rb:10:in `change'
/home/vagrant/.rbenv/versions/2.7.2/bin/bundle:23:in `load'
/home/vagrant/.rbenv/versions/2.7.2/bin/bundle:23:in `<main>'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
エラー部分のみ抜粋するとこんな感じです。
ArgumentError: Index name ‘index_migration_index_name_error_items_on_migration_index_name_error_id’ on table ‘migration_index_name_error_items’ is too long; the limit is 64 characters
indexの文字数上限は64文字なので長すぎるよ、と言われています。
これがindex名ですね。
index_migration_index_name_error_items_on_migration_index_name_error_id
このエラーの対処法を紹介していきたいと思います。
Railsでindexが貼られるパターン
上のmigrationファイルでは、t.references でテーブルを関連づけてindexを貼りました。
Railsでは他にもテーブルにindexを貼る方法があり、他の方法でも同様のエラーが発生する事があるので、そのパターンも見ていきたいと思います。
- t.references で関連づけた場合
- index: true オプションで関連づけた場合
- add_index で関連づけた場合
t.references で関連づけた場合
referencesについても、公式ドキュメントに詳細な記述がありますので興味のある方はそちらも参照してください。
migration実行時、t.referencesでテーブル同士の関連付けを行っている場合にはRails側で自動的にindexが貼られます。
上で紹介したmigrationファイルのパターンですね。
# migrationファイル
create_table :migration_index_name_error_items do |t|
# t.references :table_name で関連付けすると自動でindexを貼ってくれる
t.references :item, null: false
~~ 中略 ~~
t.timestamps
end
このような場合に、index_nameの長さでエラーが発生した場合には
indexオプションを追加する事で、index名を指定することで回避できます。
indexオプションで名前を指定する
indexというオプションがmigrationでは使用できますので
こちらを使って、index名を指定します。
書き方は、index の値にハッシュでnameを指定してあげます。
# migrationファイル
create_table :migration_index_name_error_items do |t|
# index { name: 'index_name' }でindex名を指定できる
t.references :item, null: false, index: { name: 'migration_index_name_error_items_index' }
~~ 中略 ~~
t.timestamps
end
これで、migrationを実行することで
index名の長さでエラーにならずに、migrationが通るようになります。
index: true オプションで関連づけた場合
次は、indexオプションで通常のカラムにindexを貼った場合です。
公式ドキュメント ではテーブル定義変更(change_table)のオプションとしてindexが載っていますが、テーブル作成(create_table)でも問題なく使えます。
# migrationファイル
create_table :migration_index_name_error_items do |t|
# index: true でintやstringのカラムに対してもindexを貼れる
t.integer :item_num, index: true
~~ 中略 ~~
t.timestamps
end
t.integer :item_num, index: true
のように、通常のカラムに対しても
Railsではオプションでindexを付与することができます。
name属性でindex名を指定する
referencesで紹介したのと同様に、indexオプションにname属性を追記してあげることで、index名を指定することができます。
# migrationファイル
create_table :migration_index_name_error_items do |t|
# index { name: 'index_name' }でindex名を指定できる
t.integer :item_num, index: { name: 'migration_index_name_error_items_index' }
~~ 中略 ~~
t.timestamps
end
これで、migrationを実行することで
index名の長さでエラーにならずに、migrationが通るようになります。
add_index で関連づけた場合
migrationファイルには、もう一つindexを追加する方法があります。
それが、add_indexを使う方法です。
# migrationファイル
create_table :migration_index_name_error_items do |t|
t.integer :item_num
~~ 中略 ~~
t.timestamps
end
# add_index :tabel_name, :column_name でindexを貼れる
add_index :migration_index_name_error_items, :item_num
add_indexは、一度作成したテーブルに後からindexを貼ることができます。
この方法で追加したindexが、文字数制限エラーになった場合
今まで紹介した方法と同様に、name属性を追加してindex名を指定することができます。
name属性でindex名を指定する
add_index :tabel_name, :column_name, name: ‘index_name’ で、index名を指定することができます。
# migrationファイル
create_table :migration_index_name_error_items do |t|
t.integer :item_num
~~ 中略 ~~
t.timestamps
end
# name属性を追加することで、index名を指定できる
add_index :migration_index_name_error_items, :item_num, name: 'migration_index_name_error_item_index'
nameは文字列で指定する必要があるので、“(シングルクォーテーション)で囲ってください。
これで、migrationを実行することで
index名の長さでエラーにならずに、migrationが通るようになります。
まとめ
今回は、index名の長さでエラーが発生した場合の対処法を3パターンご紹介しました。
t.references で関連づけたindex名を変更する場合
t.references :table_name, index: { name: 'index_name' }
index: true オプションで関連づけたindex名を変更する場合
t.integer :column_name, index: { name: 'index_name' }
add_indexで関連づけたindex名を変更する場合
add_index :table_name, :column_name, name: 'index_name'
どれもやっていることはほぼ同じで
referencesでもadd_indexでも、「indexオプションでname指定できるよ」ということを知ってもらえればと思います。