Gmane
Gravatar
From: Jeremy Kemper <jeremy@...>
Subject: Re: a remote database issue
Newsgroups: gmane.comp.lang.ruby.rails
Date: 2005-03-01 17:23:33 GMT (3 years, 17 weeks, 6 days, 10 hours and 14 minutes ago)
Dick Davies wrote:
> Personally I'd like to see us get away from pg_dump and find another way to
> pull the schema from development and drop everything from the test db
> (rather than dropdb/createdb).
> I'm beginning to think this should be done in the adapter..

Rails assumes a "live db" approach: work with the development db using
some kind of tool then version-control the schema dump.  The development
database is the authoritative source.

Instead, I write out the schema SQL in a text file and generate a master
db from it.  Then createdb can use the master as a template to create
the development and test databases.  Here's a sample config/database.yml
and Rakefile:

- database.yml ---
# Don't need database, etc.  Specify username and rely on .pgpass
superuser:
  username: foobar

# Contains the "master" schema and fixtures data.  Used as a template
# to create development and test database.  We don't need a username
# and other details since we won't ever connect from Rails.
fixtures:
  database: fixtures

development:
  adapter:  postgresql
  database: development
  username: foodev
  password: abc

test:
  adapter:  postgresql
  database: test
  username: footest
  password: def

- Rakefile ---
SCHEMA_SQL   = "#{RAILS_ROOT}/db/schema.pgsql"
FIXTURES_SQL = "#{RAILS_ROOT}/db/fixtures.pgsql"

desc 'Regenerate everything the master schema.'
task :regen => [:regenerate_fixtures, :fresh_dev_db, :yaml_fixtures]

desc 'Regenerate fixtures database from the master schema.'
task :regenerate_fixtures => :environment do
  conf = ActiveRecord::Base.configurations
  superuser = conf['superuser']['username']
  fixtures = conf['fixtures']['database']

  `dropdb -U #{superuser} #{fixtures}`
  `createdb -U #{superuser} #{fixtures}` or abort 'createdb failed'
  `psql -U #{superuser} -f #{SCHEMA_SQL} #{fixtures}` or abort 'schema
load failed'
  `psql -U #{superuser} -f #{FIXTURES_SQL} #{fixtures}` or abort
'fixtures load failed'
end

task(:fresh_test_db => :environment) { clone_fixtures_to :test }
task(:fresh_dev_db  => :environment) { clone_fixtures_to :development }

def clone_fixtures_to(target_label)
  conf = ActiveRecord::Base.configurations
  superuser = conf['superuser']['username']
  target, fixtures = conf[target_label.to_s]['database'],
conf['fixtures']['database']

  `dropdb -U #{superuser} #{target}`
  `createdb -U #{superuser} -T #{fixtures} #{target}`
end

desc 'Dump the fixtures database to yaml fixtures.'
task :yaml_fixtures => :environment do
  path = "#{RAILS_ROOT}/test/fixtures"
  sql = 'SELECT * FROM %s'

  ActiveRecord::Base.establish_connection(:fixtures)
  ActiveRecord::Base.connection.table_names.each do |table_name|
    i = '000'
    File.open("#{path}/#{table_name}.yml", 'wb') do |file|
      file.write ActiveRecord::Base.connection.select_all(sql %
table_name).inject({}) { |hash, record|
        hash["#{table_name}_#{i.succ!}"] = record
        hash
      }.to_yaml
    end
  end
end

Then make your test tasks depend on the :fresh_test_db task instead of
:clone_structure_to_test.  All fixtures will be loaded, so you don't
have to declare them in your test.  Instead, isolate your changes to the
test database by starting a transaction in setup and rolling back in
teardown.  This makes managing foreign key constraints simple and is
much faster than deleting and inserting all fixtures for every test.

Ramble off,
jeremy