Class: RailsInstaller::Database

Inherits:
Object
  • Object
show all
Defined in:
lib/rails-installer/databases.rb

Overview

Parent class for database plugins for the installer. To create a new database handler, subclass this class and define a yml class and optionally a create_database method.

Direct Known Subclasses

Mysql, Postgresql, Sqlite

Defined Under Namespace

Classes: Mysql, Postgresql, Sqlite

Constant Summary collapse

@@db_map =
Hash.new(self)

Class Method Summary collapse

Class Method Details

.backup(installer) ⇒ Object

Back up the database. This is fully DB and schema agnostic. It serializes all tables to a single YAML file.



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/rails-installer/databases.rb', line 35

def self.backup(installer)
  return unless connect(installer)
  
  interesting_tables = ActiveRecord::Base.connection.tables.sort - ['sessions']
  backup_dir = File.join(installer.install_directory, 'db', 'backup')
  FileUtils.mkdir_p backup_dir
  backup_file = File.join(backup_dir, "backup-#{Time.now.strftime('%Y%m%d-%H%M')}.yml")

  installer.message "Backing up to #{backup_file}"
  
  data = {}
  interesting_tables.each do |tbl|
    data[tbl] = ActiveRecord::Base.connection.select_all("select * from #{tbl}")
  end

  File.open(backup_file,'w') do |file|
    YAML.dump data, file
  end
end

.connect(installer) ⇒ Object

Connect to the database (using the ‘database.yml’ generated by the yml method). Returns true if the database already exists, and false if the database doesn’t exist yet.



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/rails-installer/databases.rb', line 14

def self.connect(installer)
  database_yml = File.read File.join(installer.install_directory, 'config', 'database.yml') rescue nil
  database_yml ||= yml(installer)
  
  environment = ENV['RAILS_ENV'] || 'development' # Mirror Rails' default.
  
  ActiveRecord::Base.establish_connection( 
    YAML.load(database_yml)[environment])
  begin
    tables = ActiveRecord::Base.connection.tables
    if tables.size > 0
      return true
    end
  rescue Exception
    # okay
  end
  return false
end

.create(installer) ⇒ Object

Create the database, including schema creation. This should be generic enough that database-specific drivers don’t need to override it.

It calls create_database to actually build a new DB from scratch if needed.



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/rails-installer/databases.rb', line 107

def self.create(installer)
  installer.message "Checking database"
  if connect(installer)
    installer.message "Database exists, preparing for upgrade"
    return
  end

  installer.message "Creating initial database"
  
  create_database(installer)
  
  schema_file = File.join(installer.install_directory,'db',"schema.#{installer.config['database']}.sql")
  schema = File.read(schema_file)
  
  # Remove comments and extra blank lines
  schema = schema.split(/\n/).map{|l| l.gsub(/^--.*/,'')}.select{|l| !(l=~/^$/)}.join("\n")
  
  schema.split(/;\n/).each do |command|
    ActiveRecord::Base.connection.execute(command)
  end
end

.create_database(installer) ⇒ Object

Create a new database from scratch. Some DBs, like SQLite, don’t need this. Others will need to override this and call the DB’s “create new database” command.



132
133
134
# File 'lib/rails-installer/databases.rb', line 132

def self.create_database(installer)
  # nothing
end

.database_yml(installer) ⇒ Object

Create a ‘database.yml’ file, using the data from yml.



93
94
95
96
97
98
99
100
# File 'lib/rails-installer/databases.rb', line 93

def self.database_yml(installer)
  yml_file = File.join(installer.install_directory,'config','database.yml')
  return if File.exists? yml_file
  
  File.open(yml_file,'w') do |f|
    f.write(yml(installer))
  end
end

.db_host(installer) ⇒ Object

Database host name



150
151
152
# File 'lib/rails-installer/databases.rb', line 150

def self.db_host(installer)
  installer.config['db_host'] || 'localhost'
end

.db_name(installer) ⇒ Object

Database name



160
161
162
# File 'lib/rails-installer/databases.rb', line 160

def self.db_name(installer)
  installer.config['db_name'] || installer.app_name
end

.db_user(installer) ⇒ Object

Database user name



155
156
157
# File 'lib/rails-installer/databases.rb', line 155

def self.db_user(installer)
  installer.config['db_user'] || ENV['USER'] || installer.app_name 
end

.dbsObject



145
146
147
# File 'lib/rails-installer/databases.rb', line 145

def self.dbs
  @@db_map
end

.inherited(sub) ⇒ Object

Inheritence hook



137
138
139
140
141
142
143
# File 'lib/rails-installer/databases.rb', line 137

def self.inherited(sub)
  name = sub.to_s.gsub(/^.*::/,'').gsub(/([A-Z])/) do |match|
    "_#{match.downcase}"
  end.gsub(/^_/,'')

  @@db_map[name] = sub
end

.restore(installer, filename) ⇒ Object

Restore a backup created by backup. Deletes all data before importing.



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/rails-installer/databases.rb', line 57

def self.restore(installer, filename)
  connect(installer)
  data = YAML.load(File.read(filename))
  
  installer.message "Restoring data"
  data.each_key do |table|
    if table == 'schema_info'
      ActiveRecord::Base.connection.execute("delete from schema_info")
      ActiveRecord::Base.connection.execute("insert into schema_info (version) values (#{data[table].first['version']})")
    else
      installer.message " Restoring table #{table} (#{data[table].size})"

      # Create a temporary model to talk to the DB
      eval %Q{
      class TempClass < ActiveRecord::Base
        set_table_name '#{table}'
        reset_column_information
      end
      }
      
      TempClass.delete_all
            
      data[table].each do |record|
        r = TempClass.new(record)
        r.id = record['id'] if record.has_key?('id')
        r.save
      end
      
      if ActiveRecord::Base.connection.respond_to?(:reset_pk_sequence!)
        ActiveRecord::Base.connection.reset_pk_sequence!(table)
      end
    end
  end
end