-
-
Notifications
You must be signed in to change notification settings - Fork 86
/
csv_importer.rb
87 lines (72 loc) · 2.23 KB
/
csv_importer.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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
class CsvImporter
attr_reader :target_model,
:temporary_file,
:processed_file_id,
:organization,
:error_details,
:error_messages,
:stats
class InvalidCategoryError < StandardError; end
def self.header_conversion(header)
header&.strip&.downcase&.gsub(' ', '_')&.gsub(/[^a-z0-9_]/, '')&.gsub(/_+/, '_')&.gsub(/^_+/, '')
end
def initialize(target_model, temporary_file, processed_file_id, organization = nil)
@target_model = target_model
@temporary_file = temporary_file
@processed_file_id = processed_file_id
@stats = Hash.new(0)
@organization = organization
@error_details = {}
@error_messages = {}
@stats[:shl_case_numbers] = Hash.new(0)
end
def call
process
end
def errored?
!error_details.empty?
end
private
def process
row_number = 2 # assuming 1 is headers
ActiveRecord::Base.transaction do
CSV.parse(
temporary_file,
headers: true,
header_converters: ->(header) { CsvImporter.header_conversion(header).to_sym },
converters: ->(value) { value&.strip },
skip_lines: /^\s*$/
).each do |csv_row|
csv_row[:processed_file_id] = processed_file_id
csv_row[:raw] = false
record = target_model.create_from_csv_data(create_attributes(csv_row.to_h))
record.cleanse_data! if record.respond_to?(:cleanse_data!)
if record.valid?
record.save!
increment_stats(record)
else
error_details["row_number_#{row_number}"] = record.errors.details
error_messages["Row #{row_number}"] = record.errors.full_messages
end
row_number += 1
end
unless error_details.empty?
@stats = Hash.new(0)
raise ActiveRecord::Rollback
end
end
end
def increment_stats(model)
stats[:row_count] += 1
if model.persisted?
stats[:rows_imported] += 1
stats[:shl_case_numbers][model.shl_case_number] += 1 if model.respond_to?(:shl_case_number)
else
stats[:rows_not_imported] += 1
end
end
def create_attributes(row_hash)
return row_hash unless organization
row_hash.merge(organization_id: organization.id)
end
end