Dumping and loading seed data for Rails database resets

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
&#91;/sourcecode&#93;

Remember to put the following line at the end of your <code>db:migrate</code> task:


Rake::Task["db:seed_data:dump"].invoke if ActiveRecord::Base.schema_format == :ruby