Rails:minitest 是否使用 schema.rb 重新创建测试模式?
Rails: does minitest use schema.rb to recreate the test schema?
我正在尝试将遗留的 Rails 系统提升到更新的标准,但是在让测试数据库反映 schema.rb
plus 的状态时遇到问题通过迁移进行的更改。
tl;dr 运行ning 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 等等非常草率。
此外,在后来的某个时候,有人决定 替换 一些常用的数字、自动递增主键 id
字段为 varchar
包含一个自生成的 GUID。字段名称仍然是 id
但它是一种新的数据类型。
但是所有数百个测试(他们 确实 编写了很多测试)都被编写为基于 ids 引用 fixture 实例,而不是 fixture 名称,并且它们之间存在依赖关系fixtures 等。他们没有更新测试,而是决定坚持使用旧模式(使用数字 id
)进行测试,并使用新模式(使用 id
中的 varchar GUID)进行生产。
OP深吸一口气...
各种环境的数据库不同步,有数百次迁移,但它们停止工作,因为 "development" 数据库是共享的,而且......你知道,这是一团糟。
我正在尝试解决所有这些问题,并最终迁移到 PostgreSQL。
我做了什么
我使用 RAILS_ENV=production rake db:structure:dump
从本地生产数据库转储了模式——这产生了一个权威的 structure.sql
。我创建了一个新的开发数据库,并使用 rake db:structure:load
加载了它的模式——我仔细比较了生产和开发模式,它们是相同的,甚至是我上面提到的 MySQL-specific unsigned int。
出于两个原因,我想改用 schema.rb
。首先,我想获得一个不依赖于 MySQL 的系统。其次,当使用 structure.sql
时,我们检查一个文件,该文件具有自动增量值、数据库设置和任何机器的其他特征 运行 最近的 db:migrate
。这会产生我希望避免的问题。
因此,我在本地将配置设置从 :sql
更改为使用 :ruby
设置来生成 schema.rb
。
但是 schema.rb
真的不喜欢将 id
字段变成 varchar
的想法 -- 我已经确保所有使用此声明的模型 self.primary_key = :id
,然后我创建了一个新的迁移来替换所有旧的,"rollup migration",其内容主要是新的 schema.rb
,但在几个方面进行了修改。
特别是,id
字段是 GUID varchar
我这样设置 table(从迁移中):
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
。
如果我在 运行ning minitest 之前检查模式 (在 drop
、create
和我的魔法迁移之后),它是正确:根据需要,时髦的主键是 varchar
。
但在测试过程中的某个地方,架构似乎正在改回 Rails 标准。我可以返回并检查 ID 列返回 int
的架构。
大概是根据实际 schema.rb
.
生成架构
这是normal/expected行为吗?关于如何实现我的目标的任何建议,很简单:
- 迁移再次起作用
- 开发、测试、登台、生产数据库在结构上是相同的
- 我现在需要忍受疯狂的
varchar
基于 GUID id
的字段
- 如果可能,我更喜欢不使用
structure.sql
好的,所以我相信以下内容是正确的:minitest,或测试 do 运行 db:schema:load
... 或 db:structure:load
当 运行ning 在 RAILS_ENV=test
时——这可以通过 运行ning rake test --trace
或 rake minitest:all --trace
.
观察到
所以,因为我的 schema.rb
不会完全重新创建数据库,因为对名为 id
的字段奇怪地使用 varchar
而不是 int
...我不得不改用 structure.sql
。
解决方案的其余部分,包括将 schema.rb
的手动修改版本添加为第一个 "rollup" 迁移效果很好,后续迁移也很好。将来某个时候,我会把这些 id 变回它们的自然形态;目前,这是一个合适的解决方案,即使不够优雅。
我正在尝试将遗留的 Rails 系统提升到更新的标准,但是在让测试数据库反映 schema.rb
plus 的状态时遇到问题通过迁移进行的更改。
tl;dr 运行ning 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 等等非常草率。
此外,在后来的某个时候,有人决定 替换 一些常用的数字、自动递增主键 id
字段为 varchar
包含一个自生成的 GUID。字段名称仍然是 id
但它是一种新的数据类型。
但是所有数百个测试(他们 确实 编写了很多测试)都被编写为基于 ids 引用 fixture 实例,而不是 fixture 名称,并且它们之间存在依赖关系fixtures 等。他们没有更新测试,而是决定坚持使用旧模式(使用数字 id
)进行测试,并使用新模式(使用 id
中的 varchar GUID)进行生产。
OP深吸一口气...
各种环境的数据库不同步,有数百次迁移,但它们停止工作,因为 "development" 数据库是共享的,而且......你知道,这是一团糟。
我正在尝试解决所有这些问题,并最终迁移到 PostgreSQL。
我做了什么
我使用 RAILS_ENV=production rake db:structure:dump
从本地生产数据库转储了模式——这产生了一个权威的 structure.sql
。我创建了一个新的开发数据库,并使用 rake db:structure:load
加载了它的模式——我仔细比较了生产和开发模式,它们是相同的,甚至是我上面提到的 MySQL-specific unsigned int。
出于两个原因,我想改用 schema.rb
。首先,我想获得一个不依赖于 MySQL 的系统。其次,当使用 structure.sql
时,我们检查一个文件,该文件具有自动增量值、数据库设置和任何机器的其他特征 运行 最近的 db:migrate
。这会产生我希望避免的问题。
因此,我在本地将配置设置从 :sql
更改为使用 :ruby
设置来生成 schema.rb
。
但是 schema.rb
真的不喜欢将 id
字段变成 varchar
的想法 -- 我已经确保所有使用此声明的模型 self.primary_key = :id
,然后我创建了一个新的迁移来替换所有旧的,"rollup migration",其内容主要是新的 schema.rb
,但在几个方面进行了修改。
特别是,id
字段是 GUID varchar
我这样设置 table(从迁移中):
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
。
如果我在 运行ning minitest 之前检查模式 (在 drop
、create
和我的魔法迁移之后),它是正确:根据需要,时髦的主键是 varchar
。
但在测试过程中的某个地方,架构似乎正在改回 Rails 标准。我可以返回并检查 ID 列返回 int
的架构。
大概是根据实际 schema.rb
.
这是normal/expected行为吗?关于如何实现我的目标的任何建议,很简单:
- 迁移再次起作用
- 开发、测试、登台、生产数据库在结构上是相同的
- 我现在需要忍受疯狂的
varchar
基于 GUIDid
的字段 - 如果可能,我更喜欢不使用
structure.sql
好的,所以我相信以下内容是正确的:minitest,或测试 do 运行 db:schema:load
... 或 db:structure:load
当 运行ning 在 RAILS_ENV=test
时——这可以通过 运行ning rake test --trace
或 rake minitest:all --trace
.
所以,因为我的 schema.rb
不会完全重新创建数据库,因为对名为 id
的字段奇怪地使用 varchar
而不是 int
...我不得不改用 structure.sql
。
解决方案的其余部分,包括将 schema.rb
的手动修改版本添加为第一个 "rollup" 迁移效果很好,后续迁移也很好。将来某个时候,我会把这些 id 变回它们的自然形态;目前,这是一个合适的解决方案,即使不够优雅。