ref: master
script/import_data
#!/usr/bin/env ruby
require 'rubygems'
require "#{File.dirname(__FILE__)}/../config/environment"
def parse_opts
puts "please provide the yaml configuration file" if ARGV.blank?
$config_file = ARGV[0]
$config = YAML.load File.read($config_file)
$options = $config['options']
$models_options = $config['models_options']
$sources = $config['sources']
$targets = $config['targets']
$mutations = {}
$renews = $config['renews']
$record_ids = {}
$id_records = {}
$temp_files = []
end
class UploadedData
attr_accessor :path, :content_type, :size
def original_filename
File.basename self.path
end
end
class ActiveRecord::Base
yaml_as "tag:ruby.yaml.org,2002:ActiveRecord"
def self.yaml_new klass, tag, val
attributes = val.delete 'attributes'
attributes = YAML.load attributes
id = attributes.delete 'id'
type = klass.name
base_type = klass.base_class.name
# target
target_type = $targets[type] || $targets[base_type] || {}
if target_id = target_type[id]
record = klass.find target_id
elsif target_other = target_type['other']
record = klass.find target_other
else
record = klass.new
end
# renew
renew_type = $renews[base_type] || {}
# id <-> record
$record_ids[record] = id
$id_records[type] ||= {}
$id_records[base_type] ||= {}
$id_records[type][id] = record
$id_records[base_type][id] = record
# embeded_file
embeded_file = val.delete 'embeded_file'
if $options['embed_files'] and embeded_file
embeded_file = YAML.load embeded_file
u = UploadedData.new; u.size = attributes['size']; u.path = attributes['filename']; u.content_type = attributes['content_type']
File.open(u.path, "wb"){ |file| file.write embeded_file }
record.uploaded_data = u
$temp_files << u.path
end
# attributes
attributes.each do |attr, value|
# target
if target_attr = target_type[attr] || $targets[attr]
if not (new_value = target_attr[value]).nil?
value = new_value
elsif not (other_value = target_attr['other']).nil?
value = other_value
end
end
# renew
if renew_attr = renew_type[attr]
$mutations[record] ||= []
renew_base_type = renew_attr['base_type']
if renew_association = renew_attr['association']
vdup = value.dup rescue value #why can't value be used?
$mutations[record] << (proc do
association = $id_records[renew_base_type][vdup] rescue nil
record.send "#{renew_association}=", association rescue nil
end)
end
value = nil
end
record[attr] = value
end
val.each do |method, value|
# RECURSION
value = YAML.load value
val[method] = value
# Fill parent
value.to_a.each do |value|
klass = value.class
type = klass.name
base_type = klass.base_class.name
target_type = $targets[type] || $targets[base_type] || {}
if belongs_to_association = target_type['belongs_to']
value.send "#{belongs_to_association}=", record
end
end
end
record
end
def call_save
self.class.record_timestamps = false
method = if ($models_options[self.class.base_class.name]['save_without_callbacks'] rescue nil) then 'create_without_callbacks' else 'create_without_timestamps' end
begin
self.send method
rescue Exception => e
puts "Could not save: #{self.inspect}"
raise
end
if $options['embed_files'] and self.respond_to? :full_filename
raise "Could not save data of: #{self.inspect}" unless File.exists? self.full_filename
end
end
end
def apply_renews
$mutations.each do |record, mutations|
mutations.each{ |mutation| mutation.call }
end
end
def run
parse_opts
ActiveRecord::Base.transaction do
YAML.load STDIN.read
# renew ids with associated records
apply_renews
# save top sources
$sources.to_a.each do |source|
record = $id_records[source['type']][source['id']]
record.call_save
pp record
end
# save others
$record_ids.keys.each do |record|
next if not record.new_record?
record.call_save
pp record
end
# delete temporary dump on Rails.root
$temp_files.each do |filename|
File.delete filename rescue nil
end
#raise 'test before!'
end
end
run