【发布时间】:2012-02-07 07:19:01
【问题描述】:
我似乎找不到允许我跳过迁移的选项或任何东西。
我知道你在想什么:“你永远不应该这样做......”
我需要跳过对我的开发数据库中不存在的特定用户记录进行更改的迁移。我不想更改迁移,因为它不是我应该使用的源的一部分。有没有办法跳过迁移或跳过失败的迁移?
提前致谢!
【问题讨论】:
标签: ruby-on-rails rake rails-migrations
我似乎找不到允许我跳过迁移的选项或任何东西。
我知道你在想什么:“你永远不应该这样做......”
我需要跳过对我的开发数据库中不存在的特定用户记录进行更改的迁移。我不想更改迁移,因为它不是我应该使用的源的一部分。有没有办法跳过迁移或跳过失败的迁移?
提前致谢!
【问题讨论】:
标签: ruby-on-rails rake rails-migrations
我认为你应该修复有问题的迁移,使其不那么脆弱,我猜几个 if 语句和一个 rescue 就足够了。
但是,如果修复迁移确实不是一种选择,您可以通过各种方式伪造它。首先,您可以只注释掉迁移方法,运行 rake db:migrate,然后取消注释(或还原)有问题的迁移。
您也可以在数据库中伪造它,但不推荐这种诡计,除非您知道自己在做什么,并且不介意在(不可避免地)犯错时手动修补。在您的数据库中有一个名为schema_migrations 的表,其中有一个名为version 的varchar(255) 列; db:migrate 使用此表来跟踪已应用的迁移。您需要做的就是插入适当的version 值,rake db:migrate 会认为迁移已经完成。找到有问题的迁移文件:
db/migrate/99999999999999_XXXX.rb
然后进入你的数据库并说:
insert into schema_migrations (version) values ('99999999999999');
其中99999999999999 当然是迁移文件名中的数字。然后运行 rake db:migrate 应该会跳过该迁移。
我会在第三个之前选择第二个选项,为了完整起见,我只包括“hack schema_versions”选项。
【讨论】:
这是解决一次性错误的好方法。
db:migrate:up VERSION=my_version
这将运行一个特定迁移的“向上”操作。 (如果需要,也有相反的情况,只需将“up”替换为“down”。)因此,您可以运行使旧迁移(您需要跳过)工作的未来迁移,或者只运行每个迁移有选择地提前迁移。
我也相信您可以通过这种方式重做迁移:
rake db:migrate:redo VERSION=my_version
我没有亲自尝试过这种方法,所以YMMV。
【讨论】:
我遇到了一个问题,我有一个迁移来添加一个已经存在的表,所以在我的情况下,我也不得不跳过这个迁移,因为我收到了错误
SQLite3::SQLException: table "posts" already exists: CREATE TABLE "posts"
我只是将 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
【讨论】:
插入所有缺失的迁移:
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) }
【讨论】:
schema_migrations表吧?
schema_migrations表只是数据库中的一个表。重新阅读您的标题,我可以看到另一种解释。我最初将其读作“您没有正确编写迁移”。我认为您的实际意思是“迁移存在问题”。但这很明显,因此问题,所以我假设“你搞砸了”的意思。我的错。
要跳过所有待处理的迁移,请在终端中运行:
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
(对于 macOS,使用 pbcopy 而不是 xclip)
然后 CTRL-V 在 rails 控制台中的结果:
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)}
然后按 ENTER。
您可以通过在执行该行之前将它们从数组 a 中删除来更改要跳过的迁移列表。
【讨论】:
您可以让您的迁移更智能,而不是跳过迁移,向它添加一些 IF,这样您就可以检查“特定用户”
【讨论】:
有时,有必要用绝对正确的迁移重新填充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
您可以将其复制粘贴到您想要的任何模型中并从控制台使用它
YourModel.insert_missing_migrations("xxxxxxxxxxxxxx")
(或其他方式)
其中"xxxxxxxxxxxxxx" - 是迁移的时间戳,在此之前您要停止插入(您可以将其留空)
!!!只有当你完全明白你会得到什么结果时才使用它!!!
【讨论】: