My all new Ruby Database Script Runner - now with Objects!

Back in December I blogged about how to access ActiveRecord & Migrations outside of Ruby on Rails. It was a little to scriptish for my liking so I've refactored it in a couple of classes instead.

Before you had to copy the code to a new file and add your database migration inside the Script.run method. I've now broken this up into a DatabaseScript class that extends ActiveRecord's Migration and has the guts of how and where to run any database commands and then any number of script classes that do the actual work.

The classes that you write on a day to day basis are now similar in style to the standard Rails Migrations:

require 'database_script'

class UniqueScriptName < DatabaseScript
def self.run
# your migration code goes here
end
end
For example I want to update my_table and set all the updated column for all rows to be true:
require 'database_script'

class UpdateMyTable < DatabaseScript
def self.run
execute('update my_table set updated = true')
end
end
If you want to use a specific database connection (rather than one of the standard Rails ones development, testing, production) then add the following method in the above class:
  def self.database_connection_details
<<-YAML
custom:
adapter: ????
database: ????
username: ????
password: ????
YAML
end
This is what the DatabaseScript class looks like:
require 'active_record'

class DatabaseScript < ActiveRecord::Migration; end

def self.script_name(script_file)
return *script_file.scan(/(.*).rb/).first
end

def script_class(script_name)
script_name.camelize.constantize
end

script_name = script_name($0)
require script_name
script_class = script_class(script_name)

# to run this within the context of a Rails app then pass your environment on the command line:
# ruby <script name>.rb development
database_type = ARGV[0]

if database_type.nil?
database_yaml = script_class.database_connection_details
else
# if you have a Rails project then place your scripts in db/script
database_yaml = IO.read('../../config/database.yml')
end

databases = YAML::load(database_yaml)

database_type = databases.keys[0] if database_type.nil?

ActiveRecord::Base.establish_connection(databases[database_type])
script_class.run
Technorati Tags: , , , ,

1 comment:

Rob Baillie said...

Good stuff.

All you need to do now is add 'Pre' and 'Post' condition checking and you're there...