1
0

Ingredient CSV import input validation

This commit is contained in:
cryptogopher 2019-09-21 22:29:04 +02:00
parent b69bdd6049
commit 3a09bf6fce
2 changed files with 81 additions and 2 deletions

View File

@ -1,4 +1,6 @@
class IngredientsController < ApplicationController
require 'csv'
before_action :find_project_by_project_id, only: [:index, :create, :import]
before_action :find_ingredient, only: [:destroy]
before_action :authorize
@ -30,6 +32,78 @@ class IngredientsController < ApplicationController
end
def import
warnings = []
if params.has_key?(:file)
quantities = @project.quantities.map { |q| [q.name, q] }.to_h
units = @project.units.map { |u| [u.shortname, u] }.to_h
ingredients = []
column_units = {}
CSV.foreach(params[:file].path, headers: true).with_index(2) do |row, line|
r = row.to_h
i = {
name: r.delete('Name'),
group: r.delete('Group') || :other,
nutrients_attributes: []
}
r.each do |col, val|
if col.blank?
warnings << "Line 1: column header missing" if line == 2
next
end
quantity, quantity_unit_sn, * = col.rstrip.partition(/\[.*\]$/)
quantity.strip!
if line == 2
unless quantities[quantity]
warnings << "Line 1: unknown quantity name #{quantity}"
end
if quantity_unit_sn.present?
column_units[quantity] = units[quantity_unit_sn[1..-2]]
warnings << "Line 1: unknown unit #{quantity_unit_sn}" \
" in column #{col}" unless column_units[quantity]
end
end
next if quantities[quantity].blank? || val.blank?
amount, amount_unit_sn, * = val.rstrip.partition(/\[.*\]$/)
unit = nil
if amount_unit_sn.present?
unit = units[amount_unit_sn[1..-2]]
warnings << "Line #{line}: unknown unit name #{amount_unit_sn}" \
" in column #{col}" unless unit
else
unit = column_units[quantity]
# Suppress row warning if column unit error has been reported eariler
unless unit || column_units.has_key?(quantity)
warnings << "Line #{line}: unknown unit for column #{col}"
end
end
if quantity == 'Reference'
i.update({
ref_amount: amount.to_d,
ref_unit: unit
})
else
i[:nutrients_attributes] << {
quantity: quantities[quantity],
amount: amount.to_d,
unit: unit
}
end
end
ingredients << i
end
else
warnings << 'No file selected'
end
if warnings.present?
warnings.unshift("Problems encountered during import - fix and try again:")
flash[:warning] = warnings.join("<br>").truncate(1024, omission: '...(and other)')
end
redirect_to project_ingredients_url(@project)
end
private

View File

@ -40,8 +40,13 @@ en:
heading_new_ingredient: 'New ingredient'
label_import_select_csv_file: 'Select CSV file'
import_hints: 'CSV file has to include header with column names. Recognized column
names are: (1) ingredient attributes (name, ref_amount, ref_unit, group),
(2) quantities names with units short names in square brackets (e.g. proteins [g])'
names are:
(1) ingredient attributes, case sensitive:
"Name" - required, "Reference" - defaults to 100[g], "Group" - defaults to "other",
(2) quantities'' names with unit short name in square brackets.
Sample header: "Name,Reference,Group,Proteins[g],Fats[g],Carbohydrates[g]".
Sample data row: "Brussels,100[g],other,3.4,300[mg],9".
Unit given in data row has precedence over that specified in header.'
form:
button_add_nutrient: 'Add nutrient'
button_delete_nutrient: 'Delete'