Rake db:test:准备任务删除开发数据库中的数据

在我的config / database.yml中使用Rails 3.2.6应用程序中的简单Rails sqlite3配置示例 ,我曾经重置我的开发数据库,​​重新播种它,并通过执行以下操作来准备我的测试数据库:

$ rake db:reset $ rake db:test:prepare 

在看了这篇关于在不同的数据库引擎上用Travis CI测试Rails应用程序的博客文章之后,我想我会试一试,所以我使用Homebrew安装了mysql和postgresql(我在OSX Snow Leopard上),设置它们根据brew info说明。 我安装了相关的gem,并按如下方式配置了数据库和Travis文件:

的Gemfile

 # ... group :development, :test do # ... gem 'sqlite3', '1.3.6' end group :test do # ... # Test mysql on Travis CI gem 'mysql2', '0.3.11' end group :test, :production do # ... # Test postgres on Travis CI and deploy on Heroku gem 'pg', '0.13.2' end 

配置/ database.yml的

 sqlite: &sqlite adapter: sqlite3 database: db/.sqlite3 mysql: &mysql adapter: mysql2 username: root password: database: my_app_ postgresql: &postgresql adapter: postgresql username: postgres password: database: my_app_ min_messages: ERROR defaults: &defaults pool: 5 timeout: 5000 host: localhost <<: * development: <<: *defaults test: &test <<: *defaults production: <<: *defaults cucumber: <<: *test 

.travis.yml

 language: ruby rvm: - 1.9.2 - 1.9.3 env: - DB=sqlite - DB=mysql - DB=postgresql script: - RAILS_ENV=test bundle exec rake --trace db:migrate - bundle exec rake db:test:prepare - bundle exec rspec spec/ before_script: - mysql -e 'create database my_app_test' - psql -c 'create database my_app_test' -U postgres bundler_args: --binstubs=./bundler_stubs 

但是,现在,当我运行rake db:reset ,在成功创建开发数据库之前,我得到一个Couldn't drop db/development.sqlite3错误消息。 因此,似乎现在有多个调用删除相同的数据库(?)。 跟踪输出看起来像:

 $ rake db:reset --trace ** Invoke db:reset (first_time) ** Invoke environment (first_time) ** Execute environment ** Execute db:reset ** Invoke db:drop (first_time) ** Invoke db:load_config (first_time) ** Invoke rails_env (first_time) ** Execute rails_env ** Execute db:load_config ** Execute db:drop Couldn't drop db/development.sqlite3 : # ** Invoke db:setup (first_time) ** Invoke db:schema:load_if_ruby (first_time) ** Invoke db:create (first_time) ** Invoke db:load_config ** Execute db:create db/development.sqlite3 already exists # ... 

这很奇怪,但至少开发数据库是创建和播种的。 真正的问题出现在我运行rake db:test:prepare :虽然没有错误消息,以及没有创建测试数据库,但是开发数据库中的数据被吹走了(尽管架构仍然很好)。 我尝试直接为命令指定Rails环境并得到:

 $ rake db:test:prepare RAILS_ENV=test You have 7 pending migrations: 20120503193649 CreateUsers # ... Run `rake db:migrate` to update your database then try again. 

运行rake db:migrate RAILS_ENV=test ,我可以再次运行我的rspec测试。 因此,我的rake命令获得相同的结果现在已更改为:

 $ rake db:reset # (with an error) $ rake db:migrate RAILS_ENV=test 

如果我将 config / database.yml 文件 更改 回一个简单的sqlite3配置, db:reset db:test:prepare 就像我期望的那样 db:test:prepare 工作。

那么,这是否意味着我的mysql和/或postgres设置导致rake任务重复和/或他们正在搞乱Rails环境设置? 我应该在哪里确认我的环境是否真的设置为与这3个数据库引擎一起正常工作?

编辑

查看Rails 3.2.8.rc2的发行说明 ,我发现ActiveRecord的更改可能与此问题相关:

  • 使用db:test:prepare和相关的rake任务时,不要将RAILS_ENV设置为development 。 这导致在使用RSpec时截断开发数据库数据。 在使用config.active_record.schema_format = :sql时,RC2再次被修复

config / application.rb有以下说明:

 # Use SQL instead of Active Record's schema dumper when creating the database. # This is necessary if your schema can't be completely dumped by the schema dumper, # like if you have constraints or database-specific column types # config.active_record.schema_format = :sql 

我的模式没有约束或数据库特定的列类型,所以我没有取消注释这一行,但是,鉴于发布说明的内容,我认为RAILS_ENV默认为development可能负责开发中删除的数据环境。 所以,我尝试了一些事情并通过我之前做的事情(在将Rails升级到3.2.8.rc2之后)得到了预期的结果:

 $ rake db:reset # (with an error) $ rake db:test:prepare RAILS_ENV=test # (with no "pending migrations" issue) 

这样做有点好,但是我仍然觉得错误,因为rake db:reset仍然存在错误,并且在运行专为测试量身定制的rake命令时必须设置RAILS_ENV=test是没有意义的数据库。

更新

由于以下修复,似乎升级到Rails 3.2.9解决了这个问题:

  • 修复rake db:test:prepare尝试将structure.sql加载到开发数据库中的问题。 修正了#8032。

Grace Liu +RafaelMendonçaFrança

我现在可以再次重置我的开发数据库,​​重新播种它,并通过执行以下操作来准备我的测试数据库:

 $ rake db:reset $ rake db:test:prepare 

您的开发数据库正在被清除,因为ActiveRecord :: Base.configurations将测试数据库设置为“development.sqlite3”。 运行rake任务时,yaml配置将被评估为ActiveRecord :: Base.configurations哈希值,此时Rails.env将设置为development。

如果RAILS_ENV = development,则test的数据库值将设置为

 database: db/development.sqlite3 

或者用于不同的适配器:

 database: my_app_development 

您可以使用简单的仅限sqlite配置重现此操作购买将database.yml中的测试块更改为以下内容:

 test: adapter: sqlite3 database: db/<%= Rails.env %>.sqlite3 pool: 5 timeout: 5000 

如果检查完整的ActiveRecord :: Base.configurations哈希,您将看到如果未指定RAILS_ENV,则将测试设置为使用开发db。 如果你要指定’生产’或’暂存’,它将被设置为。 从控制台:

 # rails c > ActiveRecord::Base.configurations['test']['database'] => "db/development.sqlite3" 

和….相比:

 # RAILS_ENV=test rails c > ActiveRecord::Base.configurations['test']['database'] => "db/test.sqlite3" 

更新

您在db:reset中看到的问题也是因为您的yaml文件被解释一次然后设置了配置。

db:reset将为给定环境调用db:drop和db:setup。 但是,如果环境是开发,它还会为测试环境执行这些任务。 因此它成功地删除了开发环境,然后当它执行测试时,配置的数据库密钥与开发部分相同,因此它不能丢弃不再存在的东西。 以下是当Rails.env ==’development’时ActiveRecord :: Base.configurations哈希的样子

 "development" => { "adapter" => "sqlite3", "database" => "db/development.sqlite3", "pool" => 5, "timeout" => 5000 }, "test" => { "adapter" => "sqlite3", "database" => "db/development.sqlite3", "pool" =>5, "timeout"=>5000 }, "production" => { "adapter" => "sqlite3", "database" => "db/development.sqlite3", "pool"=>5, "timeout"=>5000 } 

一旦它在该哈希中,它就不会返回并重新读取database.yml文件。 该hash是给定此database.yml生成的

 development: adapter: sqlite3 database: db/<%= Rails.env %>.sqlite3 pool: 5 timeout: 5000 test: adapter: sqlite3 database: db/<%= Rails.env %>.sqlite3 pool: 5 timeout: 5000 production: adapter: sqlite3 database: db/<%= Rails.env %>.sqlite3 pool: 5 timeout: 5000 

同样的问题,即开发数据库在“rake”之后被破坏。

我的出路“rake RAILS_ENV = test”。

使用ruby 1.9.3p194 Rails 3.2.7 sqlite3。