diff --git a/lib/csv_importer/column.rb b/lib/csv_importer/column.rb index 1a69773..7aa3aa6 100644 --- a/lib/csv_importer/column.rb +++ b/lib/csv_importer/column.rb @@ -6,5 +6,6 @@ class Column attribute :name, String attribute :definition, ColumnDefinition + attribute :rank, Integer, default: 0 end end diff --git a/lib/csv_importer/csv_reader.rb b/lib/csv_importer/csv_reader.rb index c5ece38..95af8bd 100644 --- a/lib/csv_importer/csv_reader.rb +++ b/lib/csv_importer/csv_reader.rb @@ -70,11 +70,11 @@ def detect_separator(csv_content) end end - # Remove trailing white spaces and ensure we always return a string + # Remove trailing white spaces, invisible characters and ensure we always return a string def sanitize_cells(rows) rows.map do |cells| cells.map do |cell| - cell ? cell.strip : "" + cell ? cell.strip.gsub(/\P{Print}|\p{Cf}/, '') : "" end end end diff --git a/lib/csv_importer/header.rb b/lib/csv_importer/header.rb index b4e550f..d3ce792 100644 --- a/lib/csv_importer/header.rb +++ b/lib/csv_importer/header.rb @@ -8,13 +8,21 @@ class Header attribute :column_names, Array[String] def columns + max_column = column_definitions.size + column_names.map do |column_name| # ensure column name escapes invisible characters - column_name = column_name.gsub(/[^[:print:]]/, '') + column_name = column_name.gsub(/\P{Print}|\p{Cf}/, '') + + # the column will be processed not in the order found in the csv + # but in the order of the importation code + # first column declared, first column processed + rank = column_definitions.index { |definition| definition.match?(column_name) } Column.new( name: column_name, - definition: find_column_definition(column_name) + definition: find_column_definition(column_name), + rank: rank || max_column ) end end diff --git a/lib/csv_importer/row.rb b/lib/csv_importer/row.rb index eb9021c..a9d3249 100644 --- a/lib/csv_importer/row.rb +++ b/lib/csv_importer/row.rb @@ -33,7 +33,7 @@ def csv_attributes # Set attributes def set_attributes(model) - header.columns.each do |column| + header.columns.sort_by(&:rank).each do |column| value = csv_attributes[column.name] begin value = value.dup if value diff --git a/lib/csv_importer/runner.rb b/lib/csv_importer/runner.rb index e4a473f..e2f976f 100644 --- a/lib/csv_importer/runner.rb +++ b/lib/csv_importer/runner.rb @@ -54,6 +54,8 @@ def persist_rows! if row.skip? tags << :skip + elsif row.errors.size > 0 + tags << :failure else if row.model.save tags << :success diff --git a/spec/csv_importer_spec.rb b/spec/csv_importer_spec.rb index e2b610d..932eab6 100644 --- a/spec/csv_importer_spec.rb +++ b/spec/csv_importer_spec.rb @@ -430,7 +430,7 @@ class ImportUserCSVByFirstName bob@example.com , true, bob ,," # insert invisible characters - csv_content.insert(-1, "\u{FEFF}") + csv_content.insert(0, "\u{FEFF}") csv_io = StringIO.new(csv_content) import = ImportUserCSV.new(file: csv_io)