Ruby-on-rails 如何跳过失败的迁移?(耙数据库:迁移)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8810732/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do you skip failed migrations? (rake db:migrate)
提问by hmind
I can't seem to find an option or anything that allows me to skip migrations.
我似乎找不到可以让我跳过迁移的选项或任何东西。
I know what you're thinking: "you should never have to do that..."
我知道你在想什么:“你不应该那样做……”
I need to skip a migration that makes changes to specific user records that don't exist in my development database. I don't want to change the migration because it is not part of the source I am supposed to be working with. Is there a way to skip a migration or skip failed migrations?
我需要跳过对我的开发数据库中不存在的特定用户记录进行更改的迁移。我不想更改迁移,因为它不是我应该使用的源的一部分。有没有办法跳过迁移或跳过失败的迁移?
Thanks in advance!
提前致谢!
回答by mu is too short
I think you should fix the offending migrations to be less fragile, I'd guess that a couple of ifstatements and perhaps a rescuewould be sufficient.
我认为您应该将有问题的迁移修复为不那么脆弱,我猜想几条if语句,也许 arescue就足够了。
But, if fixing the migrations really isn't an option, you can fake it in various ways. First of all, you could just comment out the migration methods, run rake db:migrate, and then uncomment (or revert) the offending migration.
但是,如果修复迁移确实不是一种选择,您可以通过各种方式伪造它。首先,您可以注释掉迁移方法,运行rake db:migrate,然后取消注释(或还原)有问题的迁移。
You can also fake it inside the database but this sort of chicanery is not recommended unless you know what you're doing and you don't mind manually patching things up when you (inevitably) make a mistake. There is a table in your database called schema_migrationsthat has a single varchar(255)column called version; this table is used by db:migrateto keep track of which migrations have been applied. All you need to do is INSERT the appropriate versionvalue and rake db:migratewill think that the migration has been done. Find the offending migration file:
您也可以在数据库中伪造它,但不推荐这种诡计,除非您知道自己在做什么并且不介意在(不可避免地)犯错误时手动修补。您的数据库schema_migrations中有一个名为的表,其中有一varchar(255)列名为version; 此表用于db:migrate跟踪已应用的迁移。您需要做的就是 INSERT 适当的version值,并且rake db:migrate会认为迁移已经完成。找到有问题的迁移文件:
db/migrate/99999999999999_XXXX.rb
then go into your database and say:
然后进入您的数据库并说:
insert into schema_migrations (version) values ('99999999999999');
where 99999999999999is, of course, the number from the migration's file name. Then running rake db:migrateshould skip that migration.
99999999999999当然,其中是迁移文件名中的数字。然后运行rake db:migrate应该跳过该迁移。
I'd go with the second option before the third, I'm only including the "hack schema_versions" option for completeness.
我会在第三个选项之前选择第二个选项,schema_versions为了完整性,我只包括“hack ”选项。
回答by user1647964
I had an issue where I had a migration to add a table that already existed, so in my case I had to skip this migration as well, because I was getting the error
我有一个问题,我有一个迁移来添加一个已经存在的表,所以在我的情况下,我也不得不跳过这个迁移,因为我收到了错误
SQLite3::SQLException: table "posts" already exists: CREATE TABLE "posts"
I simply commented out the content of the create table method, ran the migration, and then uncommented it out. It's kind of a manual way to get around it, but it worked. See below:
我只是简单地注释掉了 create table 方法的内容,运行了迁移,然后取消了注释。这是一种绕过它的手动方法,但它有效。见下文:
class CreatePosts < ActiveRecord::Migration
def change
# create_table :posts do |t|
# t.string :title
# t.text :message
# t.string :attachment
# t.integer :user_id
# t.boolean :comment
# t.integer :phase_id
# t.timestamps
# end
end
end
回答by John
This is a good way to do it for one-off errors.
这是解决一次性错误的好方法。
db:migrate:up VERSION=my_version
db:migrate:up VERSION=my_version
This will run one specific migration's "up" actions. (There is also the opposite if you need it, just replace "up" with "down".) So this way you can either run the future migration that makes the older one (that you need to skip) work, or just run each migration ahead of it selectively.
这将运行一个特定迁移的“向上”操作。(如果需要,也有相反的情况,只需将“up”替换为“down”即可。)这样您就可以运行未来的迁移,使旧的(您需要跳过的)工作,或者只运行每个有选择地提前迁移。
I also believe that you can redo migrations this way:
我也相信您可以通过这种方式重做迁移:
rake db:migrate:redo VERSION=my_version
rake db:migrate:redo VERSION=my_version
I have not tried that method personally, so YMMV.
我个人没有尝试过这种方法,所以YMMV。
回答by Dorian
If you have to do that, your app's migrations are messed up!
如果你必须这样做,你的应用程序的迁移就搞砸了!
Inserts all missing migrations:
插入所有丢失的迁移:
def insert(xxx)
ActiveRecord::Base.connection.execute("insert into schema_migrations (version) values (#{xxx})") rescue nil
end
files = Dir.glob("db/migrate/*")
files.collect { |f| f.split("/").last.split("_").first }.map { |n| insert(n) }
回答by Timur Nugmanov
To skip all pending migrations, run this in your terminal:
要跳过所有挂起的迁移,请在终端中运行:
echo "a = [" $(rails db:migrate:status | grep "down" | grep -o '[0-9]\{1,\}' | tr '\n' ', ') "];def insert(b);ActiveRecord::Base.connection.execute(\"insert into schema_migrations (version) values (#{b})\") rescue nil;end;a.map { |b| insert(b)}" | xclip
(For macOS use pbcopy instead of xclip)
Then CTRL-V the result inside rails console:
(对于 macOS 使用 pbcopy 而不是 xclip)
然后在 rails 控制台中使用CTRL-V 结果:
a = [ 20180927120600,20180927120700 ];def insert(b);ActiveRecord::Base.connection.execute("insert into schema_migrations (version) values (#{b})") rescue nil;end;a.map { |b| insert(b)}
And hit ENTER.
You can change the list of migrations you want to skip by removing them from array abefore executing the line.
然后按 ENTER。
您可以通过在执行该行之前从数组a 中删除它们来更改要跳过的迁移列表。
回答by okliv
sometimes, it is necessary to re-fill schema_migrationstable with definitely correct migrations...
ONLY FOR THIS PURPOSEi have created this method
有时,有必要schema_migrations使用绝对正确的迁移重新填充表......
仅出于此目的,我创建了此方法
def self.insert_missing_migrations(stop_migration=nil)
files = Dir.glob("db/migrate/*")
timestamps = files.collect{|f| f.split("/").last.split("_").first}
only_n_first_migrations = timestamps.split(stop_migration).first
only_n_first_migrations.each do |version|
sql = "insert into `schema_migrations` (`version`) values (#{version})"
ActiveRecord::Base.connection.execute(sql) rescue nil
end
end
you can copy-paste it into any model you want and use it from console
您可以将其复制粘贴到您想要的任何模型中并从控制台使用它
YourModel.insert_missing_migrations("xxxxxxxxxxxxxx")
(or somehow else)
(或以其他方式)
where "xxxxxxxxxxxxxx"- is timestamp of migration before which you want to stop insertion (you can leave it empty)
其中"xxxxxxxxxxxxxx"- 是您要停止插入之前的迁移时间戳(您可以将其留空)
!!! use it only if you absolutely understand what result will you get !!!
!!!仅当您完全了解会得到什么结果时才使用它!!!
回答by Alessandro DS
Instead of skip the migration you could make your migration smart, adding some IF to it, so you can check "specific users"
与其跳过迁移,您还可以使迁移变得智能,向其中添加一些 IF,以便您可以检查“特定用户”

