Class: ExcelImport::ExcelLoader

Inherits:
DataShift::LoaderBase
  • Object
show all
Includes:
DataShift::ExcelBase, DataShift::FileLoader
Defined in:
lib/excel_import/excel_loader.rb

Instance Method Summary collapse

Constructor Details

#initializeExcelLoader

Returns a new instance of ExcelLoader.



22
23
24
# File 'lib/excel_import/excel_loader.rb', line 22

def initialize
  super
end

Instance Method Details

#perform_load(options = {}) ⇒ Object



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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
91
92
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/excel_import/excel_loader.rb', line 37

def perform_load(options = {})

  allow_empty_rows = DataShift::Loaders::Configuration.call.allow_empty_rows

  logger.info "Starting bulk load from Excel : #{file_name}"

  start(file_name, options)

  # maps list of headers into suitable calls on the Active Record class
  bind_headers(headers)

  is_dummy_run = DataShift::Configuration.call.dummy_run

  begin
    puts 'Dummy Run - Changes will be rolled back' if is_dummy_run

    load_object_class.transaction do
      @excel.sheet_final.each_with_index do |row, current_row_idx|
        # next if current_row_idx == headers.idx
        # Excel num_rows seems to return all 'visible' rows, which appears to be greater than the actual data rows
        # (TODO - write spec to process .xls with a huge number of rows)
        #
        # manually have to detect when actual data ends, this isn't very smart but
        # got no better idea than ending once we hit the first completely empty row
        break if !allow_empty_rows && (row.nil? || row.empty?)

        logger.info "Processing Row #{current_row_idx}"

        contains_data = false

        doc_context.progress_monitor.start_monitoring
        # Iterate over the bindings,
        # For each column bound to a model operator, create a context from data in associated Excel column
        @binder.bindings.each do |method_binding|

          unless method_binding.valid?
            logger.warn("No binding was found for column (#{current_row_idx})")
            next
          end

          # If binding to a column, get the value from the cell (bindings can be to internal methods)
          value = method_binding.index ? row[method_binding.index] : nil
          context = doc_context.create_node_context(method_binding, current_row_idx, value)

          contains_data ||= context.contains_data?

          logger.info "Processing Column #{method_binding.index} (#{method_binding.pp})"
          begin
            context.process
          rescue
            if doc_context.all_or_nothing?
              logger.error('All or nothing set and Current Column failed so complete Row aborted')
              break
            end
          end

        end

        # Excel data rows not accurate, seems to have to manually detect when actual Excel data rows end
        break if !allow_empty_rows && contains_data == false
        doc_context.save_and_monitor_progress

        # unless next operation is update, reset the loader object
        doc_context.reset unless doc_context.node_context.next_update?
      end # all rows processed

      if is_dummy_run
        puts 'Excel loading stage done - Dummy run so Rolling Back.'
        raise ActiveRecord::Rollback # Don't actually create/upload to DB if we are doing dummy run
      end
    end # TRANSACTION N.B ActiveRecord::Rollback does not propagate outside of the containing transaction block

  rescue => e
    puts "ERROR: Excel loading failed : #{e.inspect}"
    raise e
  ensure
    report
  end

  puts 'Excel loading stage Complete.'
end

#run(file_name, load_class, excel_instance) ⇒ Object



26
27
28
29
30
31
32
33
34
# File 'lib/excel_import/excel_loader.rb', line 26

def run(file_name, load_class, excel_instance)
  @file_name = file_name
  @excel = excel_instance
  setup_load_class(load_class)

  logger.info("Loading objects of type #{load_object_class}")

  perform_load
end