Ingredient CSV import input validation
This commit is contained in:
parent
b69bdd6049
commit
3a09bf6fce
@ -1,4 +1,6 @@
|
|||||||
class IngredientsController < ApplicationController
|
class IngredientsController < ApplicationController
|
||||||
|
require 'csv'
|
||||||
|
|
||||||
before_action :find_project_by_project_id, only: [:index, :create, :import]
|
before_action :find_project_by_project_id, only: [:index, :create, :import]
|
||||||
before_action :find_ingredient, only: [:destroy]
|
before_action :find_ingredient, only: [:destroy]
|
||||||
before_action :authorize
|
before_action :authorize
|
||||||
@ -30,6 +32,78 @@ class IngredientsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def import
|
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
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -40,8 +40,13 @@ en:
|
|||||||
heading_new_ingredient: 'New ingredient'
|
heading_new_ingredient: 'New ingredient'
|
||||||
label_import_select_csv_file: 'Select CSV file'
|
label_import_select_csv_file: 'Select CSV file'
|
||||||
import_hints: 'CSV file has to include header with column names. Recognized column
|
import_hints: 'CSV file has to include header with column names. Recognized column
|
||||||
names are: (1) ingredient attributes (name, ref_amount, ref_unit, group),
|
names are:
|
||||||
(2) quantities names with units short names in square brackets (e.g. proteins [g])'
|
(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:
|
form:
|
||||||
button_add_nutrient: 'Add nutrient'
|
button_add_nutrient: 'Add nutrient'
|
||||||
button_delete_nutrient: 'Delete'
|
button_delete_nutrient: 'Delete'
|
||||||
|
Reference in New Issue
Block a user