Ruby on Rails

【Rails】railsでIndex name ‘xxx’ on table ‘xxx’ is too long; の対処法

rake db:migrate でテーブルを作成した時、index名が長すぎると下記のようなエラーが出ます。

Index name 'index_name' on table 'table_name' is too long; the limit is 64 characters

railsでindexが追加されるのは主にこの3つです

  1. t.references で関連づけた場合
  2. index: true オプションで関連づけた場合
  3. 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'

目次

  1. 結論
  2. 環境
  3. migrationを実行したらエラーが出た
  4. Railsでindexが貼られるパターン
  5. t.references で関連づけた場合
    1. indexオプションで名前を指定する
  6. index: true オプションで関連づけた場合
    1. name属性でindex名を指定する
  7. add_index で関連づけた場合
    1. name属性でindex名を指定する
  8. まとめ

環境

作業環境

OS: MacOS
メモリ: 32GB

Dependents
Rails6
Ruby 2.6
CentOS7 on Vagrant
Mysql 5.7

migrationを実行したらエラーが出た

Railsのmigrationについては、公式ドキュメントに詳細が載っていますので
そちらを見てみてください。

Railsドキュメント – マイグレーションとは

既存のアプリケーションに、新しいテーブルを追加するために
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を貼る方法があり、他の方法でも同様のエラーが発生する事があるので、そのパターンも見ていきたいと思います。

  1. t.references で関連づけた場合
  2. index: true オプションで関連づけた場合
  3. add_index で関連づけた場合

t.references で関連づけた場合

referencesについても、公式ドキュメントに詳細な記述がありますので興味のある方はそちらも参照してください。

Railsドキュメント – リファレンスを生成

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)でも問題なく使えます。

Railsドキュメント – テーブル定義を変更

# 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指定できるよ」ということを知ってもらえればと思います。

ピックアップ記事

  1. 【Rails】findメソッドで連想配列から指定した値を検索する
  2. 【Blender】zip版のBlenderをBlender Launcherに移…
  3. 【Blender】複数バージョンを簡単に管理できる、BlenderLaunche…
  4. 【Rails】selectメソッドで特定の条件を満たす要素を取得する
  5. 起動時の設定をカスタムする【Blender】

関連記事

 
  1. Ruby on Rails

    【Rails】Factory already registered: エラー

    railsでアプリ開発中、最新のfeatureブランチでリベースして…

  2. Ruby on Rails

    【Rails】文字列からHTMLタグを取り除く方法

    Railsで、HTMLタグを取り除いて文字列を出力したい時があります。…

  3. Ruby on Rails

    【Rails】selectメソッドで特定の条件を満たす要素を取得する

    selectは、配列に対してブロック内の条件を評価し、真になって要素を…

  4. Ruby on Rails

    【Rails】modelを作成する

    結論rails generateコマンドを使いましょ…

  5. Ruby on Rails

    【Rails】RSpecのお作法メモ

    RSpecを書く機会が増えてきたので、記法の備忘録として記事にします…

カレンダー

2024年4月
1234567
891011121314
15161718192021
22232425262728
2930  

最近の記事

  1. WordPress

    【WPテーマ自作】UnderScoresの導入
  2. Blender

    【Blender】起動時に強制終了してしまう問題
  3. Blenderの複数バージョンを簡単に管理できるBlenderLauncherの使い方

    Blender

    【Blender】複数バージョンを簡単に管理できる、BlenderLaunche…
  4. Ruby on Rails

    【Rails】modelを作成する
  5. Blender

    【Blender】zip版のBlenderをBlender Launcherに移…
PAGE TOP