我试图将一个遗留的rails系统提升到更高的当前标准,但是在让测试数据库反映schema.rb
状态以及通过迁移所做的更改时遇到了问题。
tl;dr是否运行rake minitest:all
调用与rake db:schema:load
相同的代码?
环境
钢轨3.2.20
红宝石1.9.3
微型测试宝石4.6.2
小型钢轨0.5.2
MySQL 5.1版
本地os x,测试和生产linux
原始系统状态
该系统最初是由非软件工程师、不了解rails等的人创建的。添加了一些特定于mysql的类型(例如unsigned int
),这些类型不受rails迁移和schema.rb
的特别支持。所以系统使用了structure.sql
并且对于如何保持更新、签入git等等非常草率。
此外,在稍后的某个时刻,有人决定用包含自生成guid的id
替换一些常用的数字、自动递增的主键varchar
字段。字段名仍然id
,但它是一个新的数据类型。
但是所有的数百个测试(他们确实写了很多测试)都是基于id而不是fixture名称来引用fixture实例的,fixture之间存在依赖关系,等等。他们决定不更新测试,而是使用旧的模式(数字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
机器的自动增量值、db设置和其他特性。这可能会产生我希望避免的问题。
因此,我在本地将配置设置从:sql
更改为使用:ruby
设置生成schema.rb
。
但是schema.rb
确实不喜欢将id
字段转换为varchar
的想法——我已经确定了所有使用这个declareself.primary_key = :id
的模型,然后我创建了一个新的迁移来替换所有旧的迁移,一个“汇总迁移”,其内容主要是newschema.rb
,但有几种修改。
特别是,当id
字段是guidvarchar
时,我这样设置表(从迁移中):
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"
具有大小和其他主键设置execute(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
和我的magic迁移之后)检查模式,那么是正确的:时髦的主键是varchar
所需的。但在测试过程中的某个地方,模式似乎正在被改回rails标准。我可以回去检查id列返回到
int
的模式。假设模式是从实际的
schema.rb
生成的。这是正常/预期的行为吗?关于如何实现我的目标的任何建议,这些建议很简单:
迁移又起作用了
开发、测试、登台和生产数据库在结构上是相同的
我现在需要使用疯狂的基于guid的字段
如果可能的话,我宁愿不使用
varchar
。
最佳答案
好的,所以我相信以下是正确的:minitest,或者test do rundb:schema:load
。或在db:structure:load
中运行时RAILS_ENV=test
——这可以通过运行rake test --trace
或rake minitest:all --trace
来观察。
因此,由于对名为schema.rb
的字段使用varchar
而不是int
,所以我的id
无法完全重新创建数据库。我不得不改用structure.sql
。
其余的解决方案,包括在第一次“汇总”迁移时添加一个手工修改的schema.rb
版本,效果很好,随后的迁移也很好。在将来的某个时候,我将把id转换回它们的自然形式;现在,这是一个合适的解决方案,如果不美观的话。
关于mysql - Rails:minitest是否使用schema.rb重新创建测试模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29547518/