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

Pau*_*nti 12 rake ruby-on-rails ruby-on-rails-3 travis-ci ruby-on-rails-3.2

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

$ rake db:reset
$ rake db:test:prepare 
Run Code Online (Sandbox Code Playgroud)

在看了这篇关于在不同的数据库引擎上用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
Run Code Online (Sandbox Code Playgroud)

配置/ database.yml的

sqlite: &sqlite
  adapter: sqlite3
  database: db/<%= Rails.env %>.sqlite3

mysql: &mysql
  adapter: mysql2
  username: root
  password:
  database: my_app_<%= Rails.env %>

postgresql: &postgresql
  adapter: postgresql
  username: postgres
  password:
  database: my_app_<%= Rails.env %>
  min_messages: ERROR

defaults: &defaults
  pool: 5
  timeout: 5000
  host: localhost
  <<: *<%= ENV['DB'] || "sqlite" %>

development:
  <<: *defaults

test: &test
  <<: *defaults

production:
  <<: *defaults

cucumber:
  <<: *test
Run Code Online (Sandbox Code Playgroud)

.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
Run Code Online (Sandbox Code Playgroud)

但是,现在,当我运行时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 : #<Errno::ENOENT: No such file or directory - my_app/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
# ...
Run Code Online (Sandbox Code Playgroud)

这很奇怪,但至少开发数据库是创建和播种的.真正的问题出现在我运行时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.
Run Code Online (Sandbox Code Playgroud)

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

$ rake db:reset # (with an error)
$ rake db:migrate RAILS_ENV=test
Run Code Online (Sandbox Code Playgroud)

如果我将 config/database.yml 文件 更改回一个简单的sqlite3配置,db:reset 并按 db:test:prepare 我的预期工作.

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

编辑

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

  • 不要设置RAILS_ENVdevelopment使用时,db:test:prepare以及相关的耙任务.这导致在使用RSpec时截断开发数据库数据.RC2在使用时再次固定config.active_record.schema_format = :sql

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
Run Code Online (Sandbox Code Playgroud)

我的模式没有约束或特定于数据库的列类型,所以我没有取消注释这一行,但是,考虑到发行说明的内容,我认为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)
Run Code Online (Sandbox Code Playgroud)

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

更新

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

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

Grace Liu +RafaelMendonçaFrança

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

$ rake db:reset
$ rake db:test:prepare 
Run Code Online (Sandbox Code Playgroud)

Luk*_*und 9

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

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

database: db/development.sqlite3
Run Code Online (Sandbox Code Playgroud)

或者用于不同的适配器:

database: my_app_development
Run Code Online (Sandbox Code Playgroud)

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

test:
  adapter: sqlite3
  database: db/<%= Rails.env %>.sqlite3
  pool: 5
  timeout: 5000
Run Code Online (Sandbox Code Playgroud)

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

# rails c
> ActiveRecord::Base.configurations['test']['database']
  => "db/development.sqlite3" 
Run Code Online (Sandbox Code Playgroud)

和....相比:

# RAILS_ENV=test rails c
> ActiveRecord::Base.configurations['test']['database']
  => "db/test.sqlite3"
Run Code Online (Sandbox Code Playgroud)

更新

您在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
}
Run Code Online (Sandbox Code Playgroud)

一旦它在该哈希中,它就不会返回并重新读取database.yml文件.该哈希是给定此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
Run Code Online (Sandbox Code Playgroud)