Class: Import

Inherits:
ActiveRecord::Base
  • Object
show all
Includes:
Imports::Processing, Imports::Status
Defined in:
app/models/import.rb

Direct Known Subclasses

DonationsImport, EventsImport, PeopleImport

Defined Under Namespace

Classes: RowError, RuntimeError

Constant Summary collapse

DATE_INPUT_FORMAT =
"%m/%d/%Y"
DATE_INPUT_FORMAT_WITH_TIME =
"%m/%d/%Y %l:%M%P"

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Imports::Processing

#csv_data, included, #s3_service, #time_zone_parser

Methods included from Imports::Status

#approve!, #caching!, #failed!, #failed?, #imported!, #importing!, included, #invalidate!, #pending!

Class Method Details

.build(type) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
# File 'app/models/import.rb', line 20

def self.build(type)
  case type
  when "events"
    EventsImport.new
  when "people"
    PeopleImport.new
  when "donations"
    DonationsImport.new
  else
    nil
  end
end

Instance Method Details

#attach_person(parsed_row) ⇒ Object



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'app/models/import.rb', line 134

def attach_person(parsed_row)
  ip = parsed_row
  
  person = self.people.build(parsed_row.person_attributes)
  person.organization = self.organization
  person.address = Address.new \
    :address1  => ip.address1,
    :address2  => ip.address2,
    :city      => ip.city,
    :state     => ip.state,
    :zip       => ip.zip,
    :country   => ip.country

  person.tag_list = ip.tags_list.join(", ")

  1.upto(3) do |n|
    kind = ip.send("phone#{n}_type")
    number = ip.send("phone#{n}_number")
    if kind.present? && number.present?
      person.phones << Phone.new(kind: kind, number: number)
    end
  end
  person.skip_commit = true
  person
end

#cache_dataObject



94
95
96
97
98
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
# File 'app/models/import.rb', line 94

def cache_data
  raise "Cannot load CSV data" unless csv_data.present?

  self.import_headers = nil
  self.import_rows.delete_all
  self.import_errors.delete_all

  csv_data.gsub!(/\\"(?!,)/, '""') # Fix improperly escaped quotes.

  CSV.parse(csv_data, :headers => false) do |row|
    if self.import_headers.nil?
      self.import_headers = row.to_a
      #TODO: Validate headers right here
      self.save!
    else
      self.import_rows.create!(:content => row.to_a)
      parsed_row = ParsedRow.parse(self.import_headers, row.to_a)
      
      unless row_valid?(parsed_row)
        self.invalidate! 
        return
      end
    end
  end

  self.pending!
  
#TODO: Needs to be re-worked to include the row humber in the error
rescue CSV::MalformedCSVError => e
  error_message = "There was an error while parsing the CSV document: #{e.message}"
  self.import_errors.create!(:error_message => error_message)
  self.invalidate!
rescue Exception => e
  self.import_errors.create!(:error_message => e.message)
  self.invalidate!
rescue Import::RowError => e
  self.import_errors.create!(:error_message => e.message)
  self.invalidate!
end

#fail!(error = nil, row = nil, row_num = 0) ⇒ Object

This composes errors thrown during the import. For validation errors, see invalidate!



71
72
73
74
75
# File 'app/models/import.rb', line 71

def fail!(error = nil, row = nil, row_num = 0)
  self.import_errors.create! :row_data => row, :error_message => "Row #{row_num}: #{error.message}"
  failed!
  rollback
end

#headersObject



33
34
35
# File 'app/models/import.rb', line 33

def headers
  self.import_headers
end

#importObject



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'app/models/import.rb', line 50

def import
  self.importing!

  self.people.destroy_all
  self.import_errors.delete_all

  rows.each_with_index do |row, index|
    begin
      Rails.logger.info("----- Import #{id} Processing row #{index} ------")
      process(ParsedRow.parse(headers, row))
    rescue => error
      fail!(error, row, index)
      return
    end
  end
  self.imported!
end

#parsed_rowsObject



84
85
86
87
88
89
90
91
92
# File 'app/models/import.rb', line 84

def parsed_rows
  return @parsed_rows if @parsed_rows
  @parsed_rows = []
  
  rows.each do |row|
    @parsed_rows << ParsedRow.parse(headers, row)
  end
  @parsed_rows
end

#performObject



41
42
43
44
45
46
47
48
# File 'app/models/import.rb', line 41

def perform
  if status == "caching"
    self.cache_data
  elsif status == "approved"
    self.import
    Sunspot.delay.commit
  end
end

#process(parsed_row) ⇒ Object

Subclasses must implement process and rollback



78
79
# File 'app/models/import.rb', line 78

def process(parsed_row)
end

#rollbackObject



81
82
# File 'app/models/import.rb', line 81

def rollback
end

#rowsObject



37
38
39
# File 'app/models/import.rb', line 37

def rows
  self.import_rows.map(&:content)
end