ruby-on-rails - rake 分贝 :test:prepare task deleting data in development database

标签 ruby-on-rails ruby-on-rails-3 rake ruby-on-rails-3.2 travis-ci

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

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

看了之后this blog entry关于使用 Travis CI 测试 Rails 应用程序在不同的数据库引擎上,我想我会尝试一下,所以我使用 Homebrew 安装了 mysql 和 postgresql (我在 OSX Snow Leopard 上),按照 brew info 设置它们说明。我安装了相关的gems,并配置了数据库和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

配置/数据库.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成功创建开发数据库之前的错误消息。所以,现在似乎有多次调用删除同一个数据库(?)。跟踪输出如下所示:
$ 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 环境并得到:
$ 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

如果我改变我的 配置/数据库.yml 文件返回一个简单的 sqlite3 配置,db:resetdb:test:prepare按照我的预期工作。

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

编辑

看着release notes for Rails 3.2.8.rc2 ,我发现了ActiveRecord的变化可能与这个问题有关:
  • 不设RAILS_ENVdevelopment使用时 db:test:prepare和相关的 rake 任务。这导致在使用 RSpec 时截断开发数据库数据。在 RC2 中使用 config.active_record.schema_format = :sql 时再次修复

  • 配置/应用程序.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 仍然存在错误,而且对我来说必须设置 RAILS_ENV=test 没有意义运行专门为测试数据库定制的 rake 命令时。

    更新

    由于以下修复,升级到 Rails 3.2.9 似乎解决了这个问题:
  • 修复 rake db:test:prepare 处的错误尝试将 structure.sql 加载到开发数据库中。修复 #8032。

  • Grace Liu + Rafael Mendonça Franç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 only 配置来重现这一点,将 database.yml 中的测试块更改为以下内容:
    test:
      adapter: sqlite3
      database: db/<%= Rails.env %>.sqlite3
      pool: 5
      timeout: 5000
    

    如果您检查完整的 ActiveRecord::Base.configurations 哈希,您将看到如果未指定 RAILS_ENV,则测试设置为使用开发数据库。如果您要指定“生产”或“暂存”,则将设置为该值。从控制台:
    # 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。但是,如果环境是开发环境,它也会为测试环境执行这些任务。所以它在开发环境下drop成功了,然后执行test的时候,配置的database key和开发段是一样的,所以不能drop掉不存在的东西。这是当 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 文件。该散列是给定这个 生成的。数据库.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
    

    关于ruby-on-rails - rake 分贝 :test:prepare task deleting data in development database,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11156627/

    相关文章:

    ruby-on-rails - Rails3 Routes - 将参数传递给成员路由

    ruby-on-rails-3 - 如何编写不考虑批量分配的 rspec Controller 规范 model_mock

    ruby-on-rails - 使用 Rack::Deflater 时,rails 中的 HTTP 流不起作用

    ruby - 使用 :sql 模式格式时如何使 rake db :migrate generate schema. rb

    ruby-on-rails - 如何使用回形针上传图像以外的文件...如pdf、文档

    ruby-on-rails - Rails 不再允许在路由中使用 "symbol: value"?

    ruby-on-rails - 带关联的 Ruby on Rails Activemodel

    ruby-on-rails - 范围关联元素与连接表

    ruby-on-rails - Rails 3 路由错误 : No route matches {:controller= >"user_sessions"}

    ruby-on-rails - Rails 3>在Rake任务中渲染 View