diff --git a/app/controllers/logs_controller.rb b/app/controllers/logs_controller.rb index 695475a..3c629f6 100644 --- a/app/controllers/logs_controller.rb +++ b/app/controllers/logs_controller.rb @@ -48,7 +48,7 @@ class LogsController < ApplicationController @log.source_recipe = @recipe if @log.save - render json: { success: true } + render json: { id: @log.id } else render json: @log.errors, status: :unprocessable_entity end diff --git a/app/controllers/recipes_controller.rb b/app/controllers/recipes_controller.rb index d04e22b..fd58a9c 100644 --- a/app/controllers/recipes_controller.rb +++ b/app/controllers/recipes_controller.rb @@ -48,7 +48,7 @@ class RecipesController < ApplicationController @recipe.user = current_user if @recipe.save - render json: { success: true } + render json: { id: @recipe.id } else render json: @recipe.errors, status: :unprocessable_entity end diff --git a/app/javascript/components/TheFoodCreator.vue b/app/javascript/components/TheFoodCreator.vue index 5114b71..9f464e9 100644 --- a/app/javascript/components/TheFoodCreator.vue +++ b/app/javascript/components/TheFoodCreator.vue @@ -4,7 +4,7 @@ - Cancel + Cancel diff --git a/app/javascript/components/TheLogCreator.vue b/app/javascript/components/TheLogCreator.vue index f09599c..fa89acb 100644 --- a/app/javascript/components/TheLogCreator.vue +++ b/app/javascript/components/TheLogCreator.vue @@ -8,11 +8,6 @@ -
- - Cancel -
- @@ -51,7 +46,7 @@ loadResource( api.postLog(log) - .then(() => router.push('/')) + .then(data => router.push({ name: 'log', params: { id: data.id } })) .catch(Errors.onlyFor(Errors.ApiValidationError, err => validationErrors.value = err.validationErrors())) ); } diff --git a/app/javascript/components/TheLogEditor.vue b/app/javascript/components/TheLogEditor.vue index 09b583e..588772a 100644 --- a/app/javascript/components/TheLogEditor.vue +++ b/app/javascript/components/TheLogEditor.vue @@ -8,11 +8,6 @@ -
- - Cancel -
- @@ -45,7 +40,7 @@ validationErrors.value = {}; loadResource( api.patchLog(log.value) - .then(() => router.push('/')) + .then(() => router.push({ name: 'log', params: { id: log.value.id } })) .catch(Errors.onlyFor(Errors.ApiValidationError, err => validationErrors.value = err.validationErrors())) ); } diff --git a/app/javascript/components/TheRecipeCreator.vue b/app/javascript/components/TheRecipeCreator.vue index f8a0a3d..68b7ed6 100644 --- a/app/javascript/components/TheRecipeCreator.vue +++ b/app/javascript/components/TheRecipeCreator.vue @@ -42,7 +42,7 @@ validationErrors.value = {}; loadResource( api.postRecipe(recipe.value) - .then(() => router.push('/')) + .then(data => router.push({ name: 'recipe', params: { id: data.id } })) .catch(Errors.onlyFor(Errors.ApiValidationError, err => validationErrors.value = err.validationErrors())) ); } diff --git a/lib/usda_importer.rb b/lib/usda_importer.rb index 849e505..bc0cb78 100644 --- a/lib/usda_importer.rb +++ b/lib/usda_importer.rb @@ -378,49 +378,62 @@ class UsdaImporter end build_enumerator(opened_files).each_slice(500) do |slice| - UsdaFood.transaction do - slice.each do |data| + now = Time.current + food_attrs = [] + weight_groups = [] - food = UsdaFood.new + slice.each do |data| + food = UsdaFood.new + weight_hashes = [] - data.each do |name, rows| - file_info = FILES[name] - obj = food - - rows.each do |row| - if file_info[:map_into] - obj = food.send(file_info[:map_into]).build - end - - if file_info[:static] - file_info[:static].each do |k, v| - obj.send("#{k}=", v) - end - end + data.each do |name, rows| + file_info = FILES[name] + rows.each do |row| + if file_info[:map_into] + w = {} + file_info[:static]&.each { |k, v| w[k.to_s] = v } + file_info[:map].each { |db, col| w[db.to_s] = row[col] } + weight_hashes << w + else + file_info[:static]&.each { |k, v| food.send("#{k}=", v) } if file_info[:map_function] - file_info[:map_function].call(obj, row) + file_info[:map_function].call(food, row) else - file_info[:map].each do |db, col| - obj.send("#{db}=", row[col]) - end + file_info[:map].each { |db, col| food.send("#{db}=", row[col]) } end end end + end - food.save! + attrs = food.attributes.except('id') + attrs['created_at'] = now + attrs['updated_at'] = now + food_attrs << attrs + weight_groups << weight_hashes + end + result = UsdaFood.insert_all!(food_attrs, returning: %w[id ndbn]) + id_idx = result.columns.index('id') + ndbn_idx = result.columns.index('ndbn') + ndbn_to_id = result.rows.each_with_object({}) { |row, h| h[row[ndbn_idx]] = row[id_idx] } + + all_weights = [] + food_attrs.each_with_index do |fa, i| + food_id = ndbn_to_id[fa['ndbn']] + weight_groups[i].each do |w| + all_weights << w.merge('usda_food_id' => food_id, 'created_at' => now, 'updated_at' => now) end end + UsdaFoodWeight.insert_all!(all_weights) if all_weights.any? end - ensure opened_files.each { |k, v| v.close } sorted_files.each { |k, v| `rm #{v}` } end - Food.where('ndbn != ?', '').where('ndbn IS NOT NULL').each do |i| + Food.where('ndbn != ?', '').where('ndbn IS NOT NULL').find_each do |i| i.set_usda_food(i.usda_food) i.save! end @@ -444,7 +457,7 @@ class UsdaImporter loop do break if enumerate_data.values.all? { |d| d[:done] } - current_ndbn = enumerate_data.select { |_, d| !d[:done] }.values.map { |d| d[:next_ndbn] }.min + current_ndbn = enumerate_data.select { |_, d| !d[:done] }.values.min_by { |d| d[:next_ndbn].to_i }[:next_ndbn] results = Hash.new { |hash, key| hash[key] = [] } enumerate_data.each do |name, data| diff --git a/spec/lib/usda_importer_spec.rb b/spec/lib/usda_importer_spec.rb index 40c4088..37e3a10 100644 --- a/spec/lib/usda_importer_spec.rb +++ b/spec/lib/usda_importer_spec.rb @@ -3,19 +3,45 @@ require 'usda_importer' RSpec.describe UsdaImporter do - it 'imports' do - i = UsdaImporter.new(Rails.root.join('spec', 'test_data')) - i.import + subject(:import) { UsdaImporter.new(Rails.root.join('spec', 'test_data')).import } + + it 'imports the correct number of foods with weights' do + import expect(UsdaFood.count).to eq 5 - butter = UsdaFood.where(ndbn: '01001').first + + butter = UsdaFood.find_by(ndbn: '01001') expect(butter).not_to be_nil expect(butter.usda_food_weights.count).to eq 4 - clif_bar = UsdaFood.where(ndbn: '45042066').first + clif_bar = UsdaFood.find_by(ndbn: '45042066') expect(clif_bar).not_to be_nil expect(clif_bar.usda_food_weights.count).to eq 1 + end + + it 'imports SR28 nutrition fields correctly' do + import + + butter = UsdaFood.find_by(ndbn: '01001') + expect(butter.kcal).to eq 717 + expect(butter.protein).to eq 0.85 + expect(butter.source).to eq 'sr' + end + + it 'imports branded nutrition fields via map_function' do + import + + clif_bar = UsdaFood.find_by(ndbn: '45042066') expect(clif_bar.kcal).to eq 368 + expect(clif_bar.protein).to eq 13.24 + expect(clif_bar.source).to eq 'bf' + end + + it 'updates linked Food records with usda nutrition data' do + food = create(:food, ndbn: '01001') + import + food.reload + expect(food.kcal).to eq 717 end end