Rake db:test:prepare 任务删除开发数据库中的数据 [英] Rake db:test:prepare task deleting data in development database

查看:56
本文介绍了Rake db:test:prepare 任务删除开发数据库中的数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Using a simple Rails sqlite3 configuration example in my config/database.yml for a Rails 3.2.6 app, I used to reset my development database, re-seed it, and prepare my test database simply by performing:

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

看了这篇博文 关于在不同的数据库引擎上使用 Travis CI 测试 Rails 应用程序,我想我会给它尝试一下,所以我使用 Homebrew(我在 OSX Snow Leopard 上)安装了 mysql 和 postgresql,按照brew info 说明.我安装了相关的gems,并配置了数据库和Travis文件如下:

After looking at this blog entry about testing a Rails application with Travis CI on different database engines, I thought I'd give it a try, so I installed mysql and postgresql using Homebrew (I'm on OSX Snow Leopard), set them up as per the brew info instructions. I installed the relevant gems, and configured the database and Travis files as follows:

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

config/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

.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 错误消息.所以,现在似乎有多次调用删除同一个数据库(?).跟踪输出看起来像:

Now, though, when I run rake db:reset, I get a Couldn't drop db/development.sqlite3 error message before the development database is successfully created. So, it seems that there are now multiple calls being made to drop the same database(?). The traced output looks like:

$ 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
# ...

这很奇怪,但至少开发数据库被创建和播种.当我运行 rake db:test:prepare 时,真正的问题出现了:虽然没有错误消息,也没有创建测试数据库,但开发数据库中的数据被吹走了(模式是仍然机智,虽然).我尝试直接为命令指定 Rails 环境并得到:

This is odd, but at least the development database gets created and seeded. The real issue comes when I run rake db:test:prepare: although there are no error messages, as well as the test database not being created, the data in the development database gets blown away (schema is still in tact, though). I tried directly specifying the Rails environment for the command and got:

$ 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 命令现在已更改为:

After running rake db:migrate RAILS_ENV=test, I could run my rspec tests again. So, my rake commands to get the same results have now changed to:

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

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

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

So, does this mean that my mysql and/or postgres settings are causing rake tasks to repeat and/or they're messing with the Rails environment settings? Where should I be looking to confirm if my environment is really set up to work properly with these 3 database engines?

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

Looking at the release notes for Rails 3.2.8.rc2, I found a change to ActiveRecord potentially related to this question:

  • 在使用 db:test:prepare 和相关的 rake 任务时,不要将 RAILS_ENV 设置为 development.这导致在使用 RSpec 时截断开发数据库数据.在 RC2 中使用 config.active_record.schema_format = :sql
  • 时再次被修复
  • Do not set RAILS_ENV to development when using db:test:prepare and related rake tasks. This was causing the truncation of the development database data when using RSpec. In RC2 was fixed again when using 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

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

My schema doesn't have constraints or database-specific column types, so I didn't uncomment this line, however, given the content of the release note, I wagered that RAILS_ENV defaulting to development could be responsible for the deleted data in the development environment. So, I tried out a few things and got expected results by doing what I did before (after upgrading Rails to 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 仍然存在错误,而且对我来说必须设置 没有意义RAILS_ENV=test 运行专门为测试数据库定制的 rake 命令时.

This is a bit better, but still seems wrong to me since there is still an error with rake db:reset, and it doesn't make sense to me to have to set RAILS_ENV=test when running a rake command specifically tailored for the test database.

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

It would seem that upgrading to Rails 3.2.9 solves this issue due to the following fix:

  • 修复 rake db:test:prepare 尝试将 structure.sql 加载到开发数据库中的错误.修复 #8032.
  • Fix bug where rake db:test:prepare tries to load the structure.sql into development database. Fixes #8032.

Grace Liu + Rafael Mendonça França

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

I can now again reset my development database, re-seed it, and prepare my test database simply by performing:

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

推荐答案

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

Your development database is being purged because ActiveRecord::Base.configurations has the test database set to "development.sqlite3". When the rake task is run, the yaml configuration is eval'ed into the ActiveRecord::Base.configurations hash and at that time Rails.env is set to development.

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

If RAILS_ENV=development, the database value for test will be set to

database: db/development.sqlite3

或用于不同的适配器:

database: my_app_development

您可以使用一个简单的 sqlite only 配置来重现这一点,只需将 database.yml 中的测试块更改为以下内容:

You can reproduce this with a simple sqlite only configuration buy changing the test block inside database.yml to the following:

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

如果您检查完整的 ActiveRecord::Base.configurations 哈希,您将看到如果未指定 RAILS_ENV,则测试设置为使用开发数据库.如果您要指定生产"或暂存",则将设置为该值.从控制台:

If you inspect the full ActiveRecord::Base.configurations hash you'll see that test is set to use the development db if no RAILS_ENV is specified. And if you were to specify 'production' or 'staging' it would be set to that. From the console:

# 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 文件被解释一次,然后配置被设置.

The issue you are seeing with db:reset is also because your yaml file is interpreted once and then the config is set.

db:reset 将为给定的环境调用 db:drop 和 db:setup.但是,如果环境是开发环境,它也会为测试环境执行这些任务.所以它在开发环境下drop成功了,然后执行test的时候,配置的database key和开发段是一样的,所以不能drop掉不存在的东西.这是当 Rails.env == 'development'

db:reset will invoke db:drop and db:setup for the given environment. However, if the environment is development, it also does those tasks for the test environment. So it succeeds in dropping for the development environment and then when it executes for test, the database key of the configuration is identical to the development section, hence it can't drop something that no longer exists. Here is what the ActiveRecord::Base.configurations hash looks like when Rails.env == 'development'

"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 文件.该散列是给定这个 database.yml

And once it's in that hash, it doesn't go back and re-read the database.yml file. That hash is what is generated given this 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 db:test:prepare 任务删除开发数据库中的数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆