含change_column的Rails迁移无法自动回滚,求当前可行回滚方案
我先执行了create_suppliers迁移,之后发现某个字段的数据类型有误,于是新增了如下迁移:
class ChangePhoneToStringInSuppliers < ActiveRecord::Migration[5.1] def change change_column :suppliers, :phone_no_1, :string change_column :suppliers, :phone_no_2, :string end end
执行完这个迁移后,我还没推送代码,所以理想的做法是回滚到create_suppliers迁移,直接在里面修改字段类型。但回滚ChangePhoneToStringInSuppliers迁移时遇到了如下错误:
This migration uses change_column, which is not automatically reversible. To make the migration reversible you can either:
- Define #up and #down methods in place of the #change method.
- Use the #reversible method to define reversible behavior.
我觉得错误提示和网上资料里的方法都是事前预防的方案,不是当前问题的解决办法(如果我的理解有误请指正)。请问现在该怎么回滚这个迁移?
别慌,这个情况很常见,既然自动回滚行不通,我们可以手动补全回滚逻辑或者直接强制触发回滚操作,给你两个靠谱的办法:
方法一:临时修改迁移文件,添加明确的up/down方法
因为你还没推送代码,直接修改这个迁移文件完全没问题,步骤如下:
- 打开
ChangePhoneToStringInSuppliers迁移文件,把原来的change方法替换成up和down方法:
class ChangePhoneToStringInSuppliers < ActiveRecord::Migration[5.1] def up # 这是原来的升级操作,把字段改成string change_column :suppliers, :phone_no_1, :string change_column :suppliers, :phone_no_2, :string end def down # 这里要写回滚逻辑,把字段改回原来的数据类型 # 举个例子,如果原来的类型是integer,就这么写: change_column :suppliers, :phone_no_1, :integer change_column :suppliers, :phone_no_2, :integer end end
重要提醒:
down方法里的字段类型必须和create_suppliers迁移中最初定义的类型完全一致,别搞错了!
- 现在执行回滚命令:
rails db:rollback
这样就能顺利回滚了,之后你就可以删除这个临时迁移文件,直接去修改create_suppliers里的字段类型,再重新执行rails db:migrate就完成了。
方法二:直接用版本号强制触发回滚
如果你不想修改迁移文件,也可以直接指定版本号执行回滚:
rails db:migrate:down VERSION=你的迁移版本号
这里的迁移版本号就是你那个迁移文件名开头的一串数字,比如文件名是20240520123456_change_phone_to_string_in_suppliers.rb,那版本号就是20240520123456。
执行这个命令后,系统会尝试回滚该迁移,但因为原来的change方法没有可逆逻辑,你需要手动检查数据库里的字段是否变回了原来的类型。如果没变化,你可以直接用SQL命令在数据库里修改字段类型(比如ALTER TABLE suppliers ALTER COLUMN phone_no_1 TYPE integer;),不过这种方法不如第一种稳妥,优先推荐方法一。
内容的提问来源于stack exchange,提问作者Umesh Malhotra

