TL; DR-在迁移中使用显式数据库连接会破坏可逆性。
我进行了简单的迁移,将一列添加到特定的数据库连接中:(出于充分的原因,我的应用程序有多个数据库)
class AddFlavorToBikes < ActiveRecord::Migration
def change
VehicleBase.connection.tap do |db|
db.add_column :bikes, :flavor, :string
end
end
end
这很棒:
% be rake db:migrate
== 20181120215337 AddFlavorToBikes: migrating =================================
== 20181120215337 AddFlavorToBikes: migrated (0.0060s) ========================
但是,它无法回滚:
% be rake db:rollback
== 20181120215337 AddFlavorToBikes: reverting =================================
rake aborted!
An error has occurred, this and all later migrations canceled:
PG::DuplicateColumn: ERROR: column "flavor" of relation "bikes" already exists
: ALTER TABLE "bikes" ADD "flavor" character varying/Users/david/rider-gate/db/migrate/20181120215337_add_flavor_to_bikes.rb:5:in `block in change'
/Users/david/rider-gate/db/migrate/20181120215337_add_flavor_to_bikes.rb:3:in `tap'
/Users/david/rider-gate/db/migrate/20181120215337_add_flavor_to_bikes.rb:3:in `change'
我不明白。 db.add_column的回滚应删除列。那么,为什么我要删除的字段已经存在错误? 当然存在,这就是为什么我要删除它的原因。
我在Interwebs上搜索了解决方案,甚至是遇到相同问题的任何人,也没有找到任何线索。
我尝试使用显式变量而不是.tap,但是出现了相同的错误:
class AddFlavorToBikes < ActiveRecord::Migration
def change
db = VehicleBase.connection
db.add_column :bikes, :flavor, :string
end
end
我能分辨的最接近的ActiveRecord :: Migration失去了检测它是否在除默认ActiveRecord :: Base连接之外的任何其他位置上向上或向下迁移的能力。
因此,它尝试将add_column
向上迁移,即使它处于回滚状态,也应该向下迁移。因此,它正在尝试第二次添加该列,而不是将add_column转换为remove_column。
这是在Rails 4.2.7和Ruby 2.1.9上
如何使此迁移可逆?
答案 0 :(得分:2)
通过将change
分为up
和down
方法,我找到了一个合理的解决方案:
class AddFlavorToBikes < ActiveRecord::Migration
def up
VehicleBase.connection.tap do |db|
db.add_column :bikes, :flavor, :string
end
end
def down
VehicleBase.connection.tap do |db|
db.remove_column :bikes, :flavor
end
end
end
尽管它不像可逆迁移那样优雅或干爽,但它可以使db:migrate和db:rollback成功运行。