Rake db:bootstrap and foreign keys
Posted by Sandro Paganotti in
Ruby on Rails -
comments are closed
While working on our current project I decided to implement, for the initial SQL import, the db:bootstrap task from technoweenie forum but I found some problems due to this fact:
The data is imported ordered by the name of the tables
This means that if you have a table named ‘accounts’ and a table named ‘users’ accounts data will be loaded first and users data will follow, but what happens if there is a foreign key between users table and accounts table ? ( eg: there is a column named user_id in the accounts table and you’re using the foreign key migrations plugin, or you could have scripted one foreign key in your migration files ) Well… obviously your database engine will return an error :-)
To avoid this I’ve changed a bit the bootstrap.rake file from Weenie in order to let you specify the import sequence by adding a 2 digit number in front of your filename (eg: “accounts.yml—> 10_accounts.yml”). This is the source code of the task, I know it’s quite dirty but it do its job.
namespace :bootstrap do
desc "Load initial database fixtures (in db/bootstrap/*.yml) into the current environment's database. Load specific fixtures using FIXTURES=x,y"
task :load => :environment do
require 'active_record/fixtures'
ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)
(ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir.glob(File.join(RAILS_ROOT, 'db', 'bootstrap', '*.{yml,csv}'))).sort.each do |fixture_file|
table_names = File.basename(fixture_file, '.*')
file_names = table_names
class_names = {}
fixtures_directory = 'db/bootstrap'
table_names = table_names[3..table_names.length]
table_names = [table_names].flatten.map { |n| n.to_s }
connection = ActiveRecord::Base.connection
ActiveRecord::Base.silence do
fixtures_map = {}
fixtures = table_names.map do |table_name|
fixtures_map[table_name] = Fixtures.new(connection, File.split(table_name.to_s).last, class_names[table_name.to_sym], File.join(fixtures_directory, file_names.to_s))
end
Fixtures.all_loaded_fixtures.merge! fixtures_map
connection.transaction(Thread.current['open_transactions'] == 0) do
fixtures.reverse.each { |fixture| fixture.delete_existing_fixtures }
fixtures.each { |fixture| fixture.insert_fixtures }
# Cap primary key sequences to max(pk).
if connection.respond_to?(:reset_pk_sequence!)
table_names.each do |table_name|
connection.reset_pk_sequence!(table_name)
end
end
end
end
end
end
I hope you’ll find this usefull :-)
Sandro

