开发者

RoR: how do I test my app against multiple databases?

I started deploying my latest RoR app on Heroku, which required me to start using PostgreSQL -- I'd previously been using SQLite and MySQL. I wanted a dead-simple way to continually do red/green testing against all three databases to make sure I didn't break anything in the heat of development.

What's a good way to do this?开发者_开发技巧


@awendt kindly pointed out that I could answer my own question.

It turns out the recipe is rather simple. The secret is to use a environment variable to tell Rails which db you want to use.

1. Modifying your files

In config/database.yml, include ERB constructs like this:

test:
<% if (ENV["RAILS_DB"] == "PostgreSQL") %>
  adapter: postgresql
  encoding: unicode
  database: bd_test
  pool: 5
  username: <%= ENV['POSTGRESQL_USERNAME'] || 'root' %>
  password: <%= ENV['POSTGRESQL_PASSWORD'] || '' %>
<% elsif (ENV["RAILS_DB"] == "MySQL") %>
  adapter: mysql
  encoding: utf8
  reconnect: false
  database: bd_test
  pool: 5
  username: <%= ENV['MYSQL_USERNAME'] || 'root' %>
  password: <%= ENV['MYSQL_PASSWORD'] || '' %>
  socket: <%= ENV['MYSQL_SOCKET'] || '/tmp/mysql.sock' %>
<% else %>
  # default to SQLite
  adapter: sqlite3
  database: db/test.sqlite3
  pool: 5
  timeout: 5000
<% end %>

Note 1: I've only shown it for the test environment. In fact, that's the only one I've modified, since (supposedly) it provides enough coverage to tell me if all three databases are properly supported.

Note 2: You don't need to use environment variables to set username and password -- that's just something I prefer to do since it avoids exposing passwords in a commonly viewed file.

Similarly, extend Gemfile as follows (note that your version numbers may vary):

source 'http://rubygems.org'
gem 'rails', '3.0.3'
case ENV["RAILS_DB"]
when "PostgreSQL"
  gem 'pg', '0.10.0'
when "MySQL"
  gem 'mysql2'
else
  gem 'sqlite3', '1.3.3'
  gem 'sqlite3-ruby', '1.3.3', :require => 'sqlite3'
end
...

2. Add conditions to your code

Despite the best efforts of the Rails development team, there are a few spots where ActiveRecord constructs aren't compatible across all flavors of database. In these cases, you can condition your code on ActiveRecord::Base.connection.adapter_name. Here's an example from one of my migration files:

file: migrate/20110129023453_create_cached_web_pages.rb

def self.up
  create_table :cached_web_pages do |t|
    t.string    :key             
    if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
      t.binary    :value
    else
      t.binary    :value, :limit => 16777215
    end
  end
end
...

3. Running and testing

You can now select a database simply by setting the RAILS_DB environment variable, but there's a catch: you have to run bundle install each time to set up the appropriate database adaptor from the Gemfile. Fortunately, that's exactly what the test code does. So, for example, I can run rspec's autotest in two windows:

$ RAILS_DB=SQLite autotest

and

$ RAILS_DB=PostgreSQL autotest

Now I can hack away at my files and autotest will quietly alert me if I've broken anything as I go along.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜