Class: RailsArchiver::Unarchiver

Inherits:
Object
  • Object
show all
Defined in:
lib/rails-archiver/unarchiver.rb

Defined Under Namespace

Classes: ImportError

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(model, options = {}) ⇒ Unarchiver

Returns a new instance of Unarchiver.

Parameters:

  • model (ActiveRecord::Base)
  • options (Hash) (defaults to: {})
    • logger [Logger]

    • new_copy [Boolean] if true, create all new objects instead of

      replacing existing ones.
      
    • crash_on_errors [Boolean] if true, do not do any imports if any

      models' validations failed.
      


20
21
22
23
24
25
26
27
# File 'lib/rails-archiver/unarchiver.rb', line 20

def initialize(model, options={})
  @model = model
  @logger = options.delete(:logger) || Logger.new(STDOUT)
  @options = options
  # Transport for downloading
  self.transport = _get_transport(options.delete(:transport) || :in_memory)
  self.errors = []
end

Instance Attribute Details

#errorsObject

Returns the value of attribute errors.



11
12
13
# File 'lib/rails-archiver/unarchiver.rb', line 11

def errors
  @errors
end

#transportObject

Returns the value of attribute transport.



11
12
13
# File 'lib/rails-archiver/unarchiver.rb', line 11

def transport
  @transport
end

Instance Method Details

#import_objects(klass, models) ⇒ Object

Import saved objects.

Parameters:

  • klass (Class)
  • models (Array<ActiveRecord::Base>)


76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/rails-archiver/unarchiver.rb', line 76

def import_objects(klass, models)
  cols_to_update = klass.column_names - [klass.primary_key]
  # check other unique indexes
  indexes = ActiveRecord::Base.connection.indexes(klass.table_name).
    select(&:unique)
  indexes.each { |index| cols_to_update -= index.columns }
  options = { :validate => false, :timestamps => false,
              :on_duplicate_key_update => cols_to_update }

  @logger.info("Importing #{models.length} for #{klass.name}")
  models.in_groups_of(1000).each do |group|
    klass.import(group.compact, options)
  end
rescue => e
  self.errors << "Error importing class #{klass.name}: #{e.message}"
end

#init_model(klass, hash) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/rails-archiver/unarchiver.rb', line 93

def init_model(klass, hash)
  attrs = hash.select do |x|
    klass.column_names.include?(x) && x != klass.primary_key
  end

  # fix time zone issues
  klass.columns.each do |col|
    if col.type == :datetime && attrs[col.name]
      attrs[col.name] = Time.zone.parse(attrs[col.name])
    end
  end

  model = klass.where(klass.primary_key => hash[klass.primary_key]).first
  if model.nil?
    model = klass.new
    _assign_attributes(model, attrs)
    # can't set this in the attribute hash, it'll be overridden. Need
    # to set it manually.
    model[klass.primary_key] = hash[klass.primary_key]
  else
    _assign_attributes(model, attrs)
  end

  model
end

#load_classes(hash) ⇒ Object

Load a list of general classes that were saved as JSON.

Parameters:

  • hash (Hash)


51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/rails-archiver/unarchiver.rb', line 51

def load_classes(hash)
  full_hash = hash.with_indifferent_access
  full_hash.each do |key, vals|
    begin
      save_models(key.constantize, vals)
    rescue NameError => e
      @logger.error("Could not save models for #{key}: #{e.message}")
    end
  end
  if @options[:crash_on_errors] && self.errors.any?
    raise ImportError.new("Errors occurred during load - please see 'errors' method for more details")
  end
end

#save_models(klass, hashes) ⇒ Object

Save all models into memory in the given hash on the given class.

Parameters:

  • klass (Class)

    the starting class.

  • hashes (Array<Hash<] the object hashes to import.)

    ashes [Array<Hash<] the object hashes to import.



68
69
70
71
# File 'lib/rails-archiver/unarchiver.rb', line 68

def save_models(klass, hashes)
  models = hashes.map { |hash| init_model(klass, hash) }
  import_objects(klass, models)
end

#unarchive(location = nil) ⇒ Object

Unarchive a model. Otherwise uses the existing model in the database (e.g. attribute on the model) depending on the transport being used.

Parameters:

  • location (String) (defaults to: nil)

    if given, uses the given location to unarchive.



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/rails-archiver/unarchiver.rb', line 33

def unarchive(location=nil)
  @errors = []
  source = @model ? @model.class.name : location
  @logger.info('Downloading JSON file')
  hash = @transport.retrieve_archive(location)
  @logger.info("Loading #{source}")
  load_classes(hash)
  if @model
    @model.reload
    if @model.attribute_names.include?('archived')
      @model.class.where(id: @model.id).update_all(:archived => false)
    end
  end
  @logger.info("#{source} load complete!")
end