Module: RailsBackupMigrate

Defined in:
lib/rails-backup-migrate.rb,
lib/rails-backup-migrate/version.rb

Constant Summary collapse

VERBOSE =
if ENV['verbose'] || ENV['VERBOSE']
  true
else
  false
end
VERSION =
"0.0.12"

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.backup_fileObject

Returns the value of attribute backup_file.



32
33
34
# File 'lib/rails-backup-migrate.rb', line 32

def backup_file
  @backup_file
end

Class Method Details

.add_to_archive(path) ⇒ Object

add a path to be archived. Expected path to be relative to Rails.root. This is where the archive will be created so that uploaded files (the ‘files’ dir) can be reference in place without needing to be copied.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/rails-backup-migrate.rb', line 43

def add_to_archive path
  # check it's relative to Rails.root
  raise "File '#{path}' does not exist" unless File.exist? path
  
  expanded_path = File.expand_path(path)
  if expanded_path.start_with?(rails_root.to_s)
    # remove rails_root from absolute path
    relative = expanded_path.sub(rails_root + File::SEPARATOR,'')
    # add to list
    puts "Adding relative path: '#{relative}'" if VERBOSE
    @files_to_archive << relative
  else
    raise "Cannot add a file that is not under Rails root directory. (#{expanded_path} not under #{rails_root})"
  end
end

.clean_upObject

delete any working files



74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/rails-backup-migrate.rb', line 74

def clean_up
  puts "cleaning up." if VERBOSE
  FileUtils.rmtree temp_dir
  @temp_dir = nil
  @files_to_delete_on_cleanup ||= []
  @files_to_delete_on_cleanup.each do |f|
    if File::directory? f
      FileUtils.rm_r f
    else
      FileUtils.rm f
    end
  end
  @files_to_delete_on_cleanup = []
end

.create_archive(backup_file) ⇒ Object

create the archive .tgz file in the requested location



90
91
92
93
94
95
# File 'lib/rails-backup-migrate.rb', line 90

def create_archive backup_file
  puts "creating archive..." if VERBOSE
  absolute = File::expand_path backup_file
  Dir::chdir rails_root
  `tar -czf #{absolute} #{files_to_archive.join ' '}`
end

.files_to_archiveObject



59
60
61
# File 'lib/rails-backup-migrate.rb', line 59

def files_to_archive
  @files_to_archive
end

.interesting_tablesObject

list the tables we should backup, excluding ones we can ignore



35
36
37
38
39
# File 'lib/rails-backup-migrate.rb', line 35

def interesting_tables
  ActiveRecord::Base.connection.tables.sort.reject do |tbl|
    %w(schema_migrations sessions public_exceptions).include?(tbl)
  end
end

.rails_rootObject



153
154
155
156
157
# File 'lib/rails-backup-migrate.rb', line 153

def rails_root
  # in ruby 1.9.3, `Rails.root` is a Pathname object, that plays mess with string comparisons
  # so we'll ensure we have a string
  Rails.root.to_s
end

.restore_db_from_ymlObject



138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/rails-backup-migrate.rb', line 138

def restore_db_from_yml
  FileUtils.chdir temp_dir + '/db/backup'
  
  interesting_tables.each do |tbl|

    ActiveRecord::Base.transaction do 
    
      puts "Loading #{tbl}..." if VERBOSE
      YAML.load_file("#{tbl}.yml").each do |fixture|
        ActiveRecord::Base.connection.execute "INSERT INTO #{tbl} (#{fixture.keys.map{|k| "`#{k}`"}.join(",")}) VALUES (#{fixture.values.collect { |value| ActiveRecord::Base.connection.quote(value) }.join(",")})", 'Fixture Insert'
      end        
    end
  end
end

.save_db_to_ymlObject

save the required database tables to .yml files in a folder ‘yml’ and add them to the backup



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/rails-backup-migrate.rb', line 99

def save_db_to_yml
  FileUtils.chdir rails_root
  FileUtils.mkdir_p 'db/backup'
  FileUtils.chdir 'db/backup'
  
  @files_to_delete_on_cleanup ||= []

  @mysql = ActiveRecord::Base.connection.class.to_s =~ /mysql/i

  interesting_tables.each do |tbl|
    puts "Writing #{tbl}..." if VERBOSE
    File.open("#{tbl}.yml", 'w+') do |f|
      records = ActiveRecord::Base.connection.select_all("SELECT * FROM #{tbl}")
      if @mysql
        # we need to convert Mysql::Time objects into standard ruby time objects because they do not serialise
        # into YAML on their own at all, let alone in a way that would be compatible with other databases
        records.map! do |record|
          record.inject({}) do |memo, (k,v)|
            memo[k] = case v.class.name
                        when "Mysql::Time"
                          datetime_from_mysql_time v
                        else
                          v
                      end
            memo
          end
        end
      end
      f << YAML.dump(records)
    end
    @files_to_delete_on_cleanup << File::expand_path("#{tbl}.yml")
  end
  
  # simply add the whole yml folder to the archive
  FileUtils.chdir rails_root
  add_to_archive 'db/backup'
end

.temp_dirObject

get a temp directory to be used for the backup the value is cached so it can be reused throughout the process



65
66
67
68
69
70
# File 'lib/rails-backup-migrate.rb', line 65

def temp_dir
  unless defined? @temp_dir
    @temp_dir = Dir.mktmpdir
  end
  @temp_dir
end