Database seeding, Yaml_db, Oracle, and a sequencing tweak
Back to seeding databases. My previous database seeding post addressed seeing with SQLite. This time, I’m using Oracle 11g as the back-end database, with the Oracle-Enhanced ActivieRecord adapter.
Someone pointed a Rails plugin, yaml_db, for Dumping database schemas & data, as well as loading those schemas & data into other databases. This makes it very easy to dump the database definition & data to a flat-file, and then load that into other databases. This makes it much easier to push seed and development data into other copies of a database. It also makes it trivially easy to re-image a database during development.
yaml_db makes it super easy to dump a copy of the current database with the command
rake db:dump
At some point, you’ll need to put the data dump into svn.
svn add db/data.yml svn commit db/data.yml -m "initial data seed commit"
I like to automate subsequent dumps with the series of commands, on the source schema and Ruby on Rails instance.
rake db:dump svn commit db/data.yml -m "Updated database seeds"
Then on the destination instances, the schema and data can be loaded into the destination database with the following series of commands
svn update rake db:load
However…. it appears that reset_pk_sequence doesn’t work with yaml_db and Oracle-Enhanced ActiveRecord. Upon initial glance, it looks like Oracle-Enhanced doesn’t define a method for resetting the sequences. Well… sequences have to get updated anyway…. Otherwise, future inserts via CRUD could fail, based on incorrect sequence numbers and possible duplicate IDs for the primary key.
Here is a way to do it…. I’ve put the following into my seeds.db file.
require 'find'
@@oracleFlag = ActiveRecord::Base.connection.adapter_name=="OracleEnhanced"
def resequence(obj)
puts " #{obj} Resequencing"
if obj.methods.include?(:maximum) && obj.column_names.include?('id')
puts " #{obj}, record count #{obj.count}, maximum(:id) #{obj.maximum(:id)}"
max_id = obj.maximum(:id)
next_id = max_id.nil? ? 10000 : max_id+1
seq = ""
if @@oracleFlag
begin
seq = "#{obj buy cytotec online.table_name[0..25]}_SEQ"
ActiveRecord::Base.connection.execute("DROP SEQUENCE #{seq}")
puts " #{obj.table_name} sequence #{seq} dropped"
rescue => ex
puts " #{obj.table_name} Sequence #{seq} didn't exist"
end
else # 'SQLite'
seq = "#{obj.table_name}"
end
# Recreate the sequence
seq_statement=""
if @@oracleFlag
seq_statement = "CREATE SEQUENCE #{seq} START WITH #{next_id}"
else # 'SQLite'
seq_statement = "update sqlite_sequence set seq = #{next_id} where name = '#{seq}';"
end
res = ActiveRecord::Base.connection.execute(seq_statement);
puts " #{obj.table_name} sequence #{seq} created/updated"
puts " sequence nextval #{next_id}"
puts "\n"
end
end
def get_all_models
@models= Dir['app/models/*.rb'].sort.map {|f| File.basename(f,'.*').camelize.constantize}
end
def resequence_all_models
@models= get_all_models
@models.each do |obj|
resequence(obj)
end
end
if ENV["UPDATE_SEQ"]
resequence_all_models
end
I can then reset the sequences for all of my application’s ActiveRecord models, by doing the following:
svn update rake db:load rake UPDATE_SEQ=1 db:seed