diff --git a/app/controllers/ingredients_controller.rb b/app/controllers/ingredients_controller.rb index 6989c14..7d42dad 100644 --- a/app/controllers/ingredients_controller.rb +++ b/app/controllers/ingredients_controller.rb @@ -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("
").truncate(1024, omission: '...(and other)') + end + redirect_to project_ingredients_url(@project) end private diff --git a/config/locales/en.yml b/config/locales/en.yml index 53324f9..bc4c672 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -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'