Ruby on Rails执行db:rollback时索引参数错误求助
Rails db:rollback 失败:找不到指定索引的解决方案
问题场景
我创建了如下数据库迁移模型:
class CreateStoreComments < ActiveRecord::Migration[7.0] def change create_table :store_comments do |t| t.text :comment t.references :store_post, null: false, foreign_key: true t.references :user, null: false, foreign_key: true t.timestamps end add_index :store_comments, [:user_id, :created_at] end end
操作步骤:
- 执行
rails generate model StoreComment comment:text store_post:references user:references生成模型 - 在迁移文件中添加上述索引代码后执行
rails db:migrate完成迁移 - 执行
rails db:rollback时触发错误:
D:\ruby_projects\myapp-main>rails db:rollback == 20231023131530 CreateStoreComments: reverting ============================== -- remove_index(:store_comments, [:user_id, :created_at]) rails aborted! StandardError: An error has occurred, this and all later migrations canceled: No indexes found on store_comments with the options provided. Caused by: ArgumentError: No indexes found on store_comments with the options provided. Tasks: TOP => db:rollback (See full trace by running task with --trace)
当前store_comments的数据库schema如下:
create_table "store_comments", force: :cascade do |t| t.text "comment" t.integer "store_post_id", null: false t.integer "user_id", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index "\"store_id\", \"user_id\", \"created_at\"", name: "index_store_comments_on_store_id_and_user_id_and_created_at" t.index ["store_post_id"], name: "index_store_comments_on_store_post_id" t.index ["user_id"], name: "index_store_comments_on_user_id" end
问题原因
从schema可见,数据库中实际存在的复合索引是index_store_comments_on_store_id_and_user_id_and_created_at,包含store_id、user_id、created_at三个字段,但迁移文件中定义的是仅包含user_id和created_at的索引。这说明迁移执行后,可能存在手动修改schema或其他迁移操作,导致原迁移定义的索引未被创建,反而生成了额外的三字段索引,最终回滚时找不到要删除的目标索引。
解决方法
方法1:修正迁移文件匹配现有索引
如果这个三字段索引是业务需要的,直接修改迁移文件的索引定义,使其与实际存在的索引一致:
class CreateStoreComments < ActiveRecord::Migration[7.0] def change create_table :store_comments do |t| t.text :comment t.references :store_post, null: false, foreign_key: true t.references :user, null: false, foreign_key: true # 若store_id是必要字段,需在此添加对应定义 t.references :store, null: false, foreign_key: true t.timestamps end # 替换为实际的三字段索引 add_index :store_comments, [:store_id, :user_id, :created_at] end end
修改后可重新执行迁移(若需要),再尝试rails db:rollback。
方法2:手动调整数据库索引后回滚
- 进入数据库控制台:执行
rails dbconsole - 删除多余的三字段索引:
DROP INDEX index_store_comments_on_store_id_and_user_id_and_created_at;
- 创建迁移文件中定义的索引:
CREATE INDEX index_store_comments_on_user_id_and_created_at ON store_comments (user_id, created_at);
- 再次执行
rails db:rollback即可正常回滚。
方法3:显式定义回滚逻辑
保留原迁移的change方法,新增down方法明确指定要删除的索引名称:
class CreateStoreComments < ActiveRecord::Migration[7.0] def change create_table :store_comments do |t| t.text :comment t.references :store_post, null: false, foreign_key: true t.references :user, null: false, foreign_key: true t.timestamps end add_index :store_comments, [:user_id, :created_at] end def down # 直接指定数据库中实际存在的索引名称 remove_index :store_comments, name: "index_store_comments_on_store_id_and_user_id_and_created_at" drop_table :store_comments end end
修改后执行rails db:rollback即可完成回滚。
内容的提问来源于stack exchange,提问作者John Sall
相关产品推荐
相关产品推荐

