As mentioned in our previous posts regarding database migrations in Rails, we have introduced a method of managing seed data in migrations. Although this methodology still has some problems, generally speaking it works pretty well.
After a database migration, a schema dump takes place. This allows fast recreation of databases without having to go through every single migration. The problem with this is that any seed data added during the migrations is not added back in when doing a db:reset. This can be solved by having a similar function to Schema Dumper.
Here are the seed data tasks (you probably want to add these into the db namespace):
namespace :seed_data do
desc 'Load schema seed data'
task :load => :environment do
puts "== Loading dumped seed data"
config = ActiveRecord::Base.configurations[RAILS_ENV || 'development']
ActiveRecord::Base.establish_connection(config)
require 'active_record/fixtures'
Dir.glob(RAILS_ROOT + '/db/seed_data/global/*.yml').each do |file|
Fixtures.create_fixtures(RAILS_ROOT + '/db/seed_data/global', File.basename(file, '.*'))
end
end
desc 'Save schema seed datae'
task :dump => :environment do
config = ActiveRecord::Base.configurations[RAILS_ENV || 'development']
ActiveRecord::Base.establish_connection(config)
Database::SeedDataDumper.dump(ActiveRecord::Base.connection)
end
end
You’ll need the SeedDataDumper class:
module Database
class SeedDataDumper
def self.dump(connection)
new(connection).dump()
true
end
def dump()
@connection.tables.each do |table|
if @connection.select_all("DESCRIBE #{table}").inject(false) { |b, col| b || (col["Field"]=="came_from_migration") }
data = @connection.select_all("SELECT * FROM #{table} WHERE came_from_migration IS NOT NULL")
if !data.empty?
outfile = File.new("#{@folder}/#{table}.yml", "w")
header(outfile)
i = "0"
outfile.write data.inject({}) { |hash, record|
hash["#{table}_#{i.succ!}"] = record
hash
}.to_yaml
footer(outfile)
end
end
end
end
private
def initialize(connection)
@connection = connection
@folder = "#{RAILS_ROOT}/db/seed_data"
puts "== Dumping seed data"
end
def header(stream)
stream.puts <<HEADER
# This file is auto-generated from all the current "came_from_migration" rows in the selected
# database. It generates a yaml file per table which can be loaded in again using fixtures.
HEADER
end
def footer(stream)
stream
end
end
end
Remember to put the following line at the end of your db:migrate task:
Rake::Task["db:seed_data:dump"].invoke if ActiveRecord::Base.schema_format == :ruby