class RailsArchiver::Unarchiver

Attributes

errors[RW]
transport[RW]

Public Class Methods

new(model, options={}) click to toggle source

@param model [ActiveRecord::Base] @param options [Hash]

* 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.
# 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

Public Instance Methods

import_objects(klass, models) click to toggle source

Import saved objects. @param klass [Class] @param models [Array<ActiveRecord::Base>]

# File lib/rails-archiver/unarchiver.rb, line 72
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) click to toggle source
# File lib/rails-archiver/unarchiver.rb, line 89
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) click to toggle source

Load a list of general classes that were saved as JSON. @param hash [Hash]

# File lib/rails-archiver/unarchiver.rb, line 51
def load_classes(hash)
  full_hash = hash.with_indifferent_access
  full_hash.each do |key, vals|
    save_models(key.constantize, vals)
  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) click to toggle source

Save all models into memory in the given hash on the given class. @param klass [Class] the starting class. @param hashes [Array<Hash<] the object hashes to import.

# File lib/rails-archiver/unarchiver.rb, line 64
def save_models(klass, hashes)
  models = hashes.map { |hash| init_model(klass, hash) }
  import_objects(klass, models)
end
unarchive(location=nil) click to toggle source

Unarchive a model. @param location [String] if given, uses the given location to unarchive. Otherwise uses the existing model in the database (e.g. attribute on the model) depending on the transport being used.

# 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.update_attribute(:archived, false)
    end
  end
  @logger.info("#{source} load complete!")
end

Private Instance Methods

_assign_attributes(model, attrs) click to toggle source

@param model [ActiveRecord::Base] @param attrs [Hash]

# File lib/rails-archiver/unarchiver.rb, line 119
def _assign_attributes(model, attrs)
  if model.method(:attributes=).arity == 1
    model.attributes = attrs
  else
    model.send(:attributes=, attrs, false)
  end
end
_get_transport(symbol_or_object) click to toggle source
# File lib/rails-archiver/unarchiver.rb, line 127
def _get_transport(symbol_or_object)
  if symbol_or_object.is_a?(Symbol)
    klass = if symbol_or_object.present?
              "RailsArchiver::Transport::#{symbol_or_object.to_s.classify}".constantize
              else
                Transport::InMemory
            end
    klass.new(@model, @logger)
  else
    symbol_or_object
  end
end