我试图让传统的Rails系统达到更新的标准,但是在测试数据库反映schema.rb的状态以及通过迁移进行的更改方面遇到了问题.
tl; dr运行rake minitest:all调用与rake db:schema:load相同的代码?
环境
> Rails 3.2.20
> Ruby 1.9.3
> Minitest gem 4.6.2
> minitest-rails 0.5.2
> MySQL 5.1
>本地OS X,测试和生产Linux
原始系统状态
该系统最初由非软件工程师,不知道Rails等人员建立.添加了几种特定于MySQL的类型(例如unsigned int),这些类型并未使用Rails的迁移和schema.rb特别支持.所以系统使用了structure.sql,并且对于如何保持更新,检入git等等非常草率.
此外,在某些时候,有人决定用包含自生成GUID的varchar替换一些通常的数字,自动递增主键id字段.字段名称仍然是id,但它是一种新的数据类型.
但是所有的数百个测试(他们确实写了很多测试)已经写入基于id的参考夹具实例,而不是夹具名称,夹具之间存在依赖关系等.他们决定坚持使用,而不是更新测试.用于测试的旧模式(带有数字id),并使用新模式(在id中使用varchar GUID)进行生产.
OP深呼吸……
各种环境的数据库不同步,有数百次迁移,但由于共享了“开发”数据库,它们停止了工作……你知道,这是一团糟.
我试图修复所有这些,并最终转移到PostgreSQL.
我做了什么
我使用RAILS_ENV = production rake db:structure:dump在本地从生产数据库中转储了模式 – 这产生了一个权威的structure.sql.我创建了一个新的开发数据库,并使用rake db:structure:load加载了它的模式 – 我仔细比较了生产和开发模式,它们是相同的,甚至是我上面提到的特定于MySQL的unsigned int.
我想转向使用schema.rb有两个原因.首先,我想进入一个不依赖于MySQL的系统.其次,当使用structure.sql时,我们检查一个文件,该文件具有自动增量值,数据库设置以及运行最新db:migrate的任何机器的其他特性.这可能会产生我宁愿避免的问题.
因此,我在本地更改了配置设置:sqlto使用:ruby设置生成schema.rb.
但schema.rb真的不喜欢将id字段转换为varchar的想法 – 我确保所有使用它的模型声明self.primary_key =:id,然后我创建了一个新的迁移来替换所有旧的,“汇总迁移”,其内容主要是新的schema.rb,但在几个方面进行了修改.
特别是,如果id字段是GUID varchar,我就像这样设置表(从迁移中):
class RolledUpStateAsOf20150403 < ActiveRecord::Migration
def up
# ... all other table definitions in the system
create_table "users", :id => false, :force => false do |t|
t.string "id", :limit => 36, :default => "", :null => false
t.string "login"
# and all the other user fields
end
execute("ALTER TABLE users ADD PRIMARY KEY (id);")
#...
end
def down
raise ActiveRecord::IrreversibleMigration
end
end
所以:
>:id => false以防止迁移创建正常ID
>:force => false以确保此迁移不会破坏生产数据库
> t.string“id”,带有大小和其他类似主键的设置
>在末尾执行(ALTER TABLE …)以将id声明为主键
每次我在将来创建一个新的迁移时,schema.rb都会更新 – 它现在不准确(直到我们以后摆脱那些古怪的id字段).迁移将尊重正常的Rails实践.
一旦生产,登台,开发和其他数据库同步,那么一切都很顺利.
除了我们测试.
那么为什么当我运行Minitest时这不起作用?
我正在使用minitest运行测试,如下所示:
RAILS_ENV=test rake db:drop
RAILS_ENV=test rake db:create
RAILS_ENV=test rake db:migrate
RAILS_ENV=test rake minitest:all
但后来我开始看到错误,错误是由于id列被定义为int而不是varchar.
如果我在运行minitest之前检查架构(在drop,create和my magic migration之后),那就是正确的:根据需要,时髦的主键是varchar.
但是在测试期间的某个地方看起来模式正在变回Rails标准.我可以返回并检查ID列返回int的模式.
据推测,模式是从实际的schema.rb生成的.
这是正常/预期的行为吗?关于如何实现我的目标的任何建议,简单地说:
>迁移再次工作
>开发,测试,分期,生产数据库在结构上是相同的
>我现在需要使用疯狂的varchar基于GUID的id字段
>如果可能的话,我不想使用structure.sql
最佳答案 好的,所以我相信以下是真的:minitest,或者测试运行db:schema:load …或db:structure:在RAILS_ENV = test中运行时加载 – 这可以通过运行rake测试来观察 – 追踪或耙minitest:全部–trace.
所以,因为我的schema.rb不会完全重新创建数据库,因为varchar而不是int用于名为id的字段…我不得不恢复使用structure.sql.
解决方案的其余部分,包括添加手动修改版本的schema.rb作为第一个“汇总”迁移工作很好,后续迁移很好.未来的某个时候,我会把ids变回自然形态;目前,这是一个合适的解决方案,如果不是优雅的话.