Added long descirption to usda foods

This commit is contained in:
Dan Elbert 2016-01-28 18:18:45 -06:00
parent 70e7a8b415
commit 2dca779294
13 changed files with 8859 additions and 27 deletions

View File

@ -95,7 +95,7 @@ class IngredientsController < ApplicationController
end end
def usda_food_search def usda_food_search
@foods = UsdaFood.search(params[:query]).limit(50) @foods = UsdaFood.search(params[:query]).limit(50).order(:long_description)
respond_to do |format| respond_to do |format|
format.html { render :layout => false } format.html { render :layout => false }

View File

@ -7,7 +7,7 @@ class UsdaFood < ActiveRecord::Base
if tokens.empty? if tokens.empty?
UsdaFood.none UsdaFood.none
else else
UsdaFood.matches_tokens(:short_description, tokens) UsdaFood.matches_tokens(:long_description, tokens)
end end
end end

View File

@ -21,7 +21,7 @@
<span class="glyphicon glyphicon-link"></span><span class="ndbn"><%= @ingredient.ndbn %></span> <span class="glyphicon glyphicon-link"></span><span class="ndbn"><%= @ingredient.ndbn %></span>
</button> </button>
</div> </div>
<p class="form-control-static" style="padding-left: 7px;"><%= @ingredient.ndbn ? UsdaFood.find_by_ndbn(@ingredient.ndbn).short_description : '' %></p> <p class="form-control-static" style="padding-left: 7px;"><%= @ingredient.ndbn ? UsdaFood.find_by_ndbn(@ingredient.ndbn).long_description : '' %></p>
</div> </div>
</div> </div>

View File

@ -12,7 +12,7 @@
<tr> <tr>
<th><%= f.ndbn %></th> <th><%= f.ndbn %></th>
<th><%= link_to f.short_description, '#', class: 'food_result', data: {ndbn: f.ndbn} %></th> <th><%= link_to f.long_description, '#', class: 'food_result', data: {ndbn: f.ndbn} %></th>
</tr> </tr>
<% end %> <% end %>

View File

@ -2,6 +2,6 @@
json.array! @foods do |f| json.array! @foods do |f|
json.extract! f, :ndbn json.extract! f, :ndbn
json.name f.short_description json.name f.long_description
end end

View File

@ -3,8 +3,8 @@ class CreateUsdaFood < ActiveRecord::Migration
create_table :usda_foods do |t| create_table :usda_foods do |t|
t.string :ndbn, limit: 5, index: :unique, null: false t.string :ndbn, limit: 5, index: :unique, null: false
t.string :long_description, index: true
t.string :short_description, index: true t.string :short_description
t.decimal :water, precision: 10, scale: 2 t.decimal :water, precision: 10, scale: 2
t.integer :kcal t.integer :kcal
t.decimal :protein, precision: 10, scale: 2 t.decimal :protein, precision: 10, scale: 2
@ -17,7 +17,9 @@ class CreateUsdaFood < ActiveRecord::Migration
t.decimal :gram_weight_2, precision: 9, scale: 2 t.decimal :gram_weight_2, precision: 9, scale: 2
t.string :gram_weight_desc_1 t.string :gram_weight_desc_1
t.string :gram_weight_desc_2 t.string :gram_weight_desc_2
t.string :refuse_description
t.integer :refuse_percent t.integer :refuse_percent
t.string :scientific_name
t.timestamps null: false t.timestamps null: false
end end

View File

@ -69,6 +69,7 @@ ActiveRecord::Schema.define(version: 20160124231837) do
create_table "usda_foods", force: :cascade do |t| create_table "usda_foods", force: :cascade do |t|
t.string "ndbn", limit: 5, null: false t.string "ndbn", limit: 5, null: false
t.string "long_description"
t.string "short_description" t.string "short_description"
t.decimal "water", precision: 10, scale: 2 t.decimal "water", precision: 10, scale: 2
t.integer "kcal" t.integer "kcal"
@ -82,13 +83,15 @@ ActiveRecord::Schema.define(version: 20160124231837) do
t.decimal "gram_weight_2", precision: 9, scale: 2 t.decimal "gram_weight_2", precision: 9, scale: 2
t.string "gram_weight_desc_1" t.string "gram_weight_desc_1"
t.string "gram_weight_desc_2" t.string "gram_weight_desc_2"
t.string "refuse_description"
t.integer "refuse_percent" t.integer "refuse_percent"
t.string "scientific_name"
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
end end
add_index "usda_foods", ["long_description"], name: "index_usda_foods_on_long_description"
add_index "usda_foods", ["ndbn"], name: "index_usda_foods_on_ndbn" add_index "usda_foods", ["ndbn"], name: "index_usda_foods_on_ndbn"
add_index "usda_foods", ["short_description"], name: "index_usda_foods_on_short_description"
create_table "users", force: :cascade do |t| create_table "users", force: :cascade do |t|
t.string "username" t.string "username"

View File

@ -33,7 +33,7 @@ Ingredient.create!([
User.create!({username: 'dan', full_name: 'Dan', email: 'dan.elbert@gmail.com', password: 'qwerty', password_confirmation: 'qwerty'}) User.create!({username: 'dan', full_name: 'Dan', email: 'dan.elbert@gmail.com', password: 'qwerty', password_confirmation: 'qwerty'})
importer = UsdaImporter.new(Rails.root.join('vendor', 'data', 'usda', 'ABBREV.txt')) importer = UsdaImporter.new(Rails.root.join('vendor', 'data', 'usda'))
importer.import importer.import

View File

@ -2,7 +2,7 @@ namespace :usda do
desc 'Empties usda_foods table, imports all data, and then updates any linked ingredients' desc 'Empties usda_foods table, imports all data, and then updates any linked ingredients'
task import: :environment do task import: :environment do
importer = UsdaImporter.new(Rails.root.join('vendor', 'data', 'usda', 'ABBREV.txt')) importer = UsdaImporter.new(Rails.root.join('vendor', 'data', 'usda'))
importer.import importer.import
end end
end end

View File

@ -2,7 +2,7 @@ require 'csv'
class UsdaImporter class UsdaImporter
COLUMNS = [ ABBREV_COLUMNS = [
'NDB_No', 'NDB_No',
'Shrt_Desc', 'Shrt_Desc',
'Water', 'Water',
@ -57,8 +57,25 @@ class UsdaImporter
'GmWt_Desc2', 'GmWt_Desc2',
'Refuse_Pct' 'Refuse_Pct'
] ]
FOOD_DATA_COLUMNS = [
'NDB_No',
'FdGrp_Cd',
'Long_Desc',
'Shrt_Desc',
'ComName',
'ManufacName',
'Survey',
'Ref_desc',
'Refuse',
'SciName',
'N_Factor',
'Pro_Factor',
'Fat_Factor',
'CHO_Factor'
]
COLUMN_MAP = { ABBREV_COLUMN_MAP = {
ndbn: 'NDB_No', ndbn: 'NDB_No',
short_description: 'Shrt_Desc', short_description: 'Shrt_Desc',
water: 'Water', water: 'Water',
@ -76,20 +93,40 @@ class UsdaImporter
refuse_percent: 'Refuse_Pct' refuse_percent: 'Refuse_Pct'
} }
def initialize(file) FOOD_DATA_COLUMN_MAP = {
@file = file scientific_name: 'SciName',
refuse_description: 'Ref_desc',
long_description: 'Long_Desc'
}
def initialize(directory)
@directory = directory
end end
def import def import
UsdaFood.delete_all UsdaFood.delete_all
CSV.open(@file, 'r:iso-8859-1:utf-8', csv_options) do |csv| food_data_lookup = {}
CSV.open(File.join(@directory, 'FOOD_DES.txt'), 'r:iso-8859-1:utf-8', csv_options(FOOD_DATA_COLUMNS)) do |csv|
csv.each do |row|
food_data_lookup[row['NDB_No']] = row.to_h
end
end
CSV.open(File.join(@directory, 'ABBREV.txt'), 'r:iso-8859-1:utf-8', csv_options(ABBREV_COLUMNS)) do |csv|
csv.each_slice(500) do |slice| csv.each_slice(500) do |slice|
UsdaFood.transaction do UsdaFood.transaction do
attributes = slice.map do |row| attributes = slice.map do |row|
Hash[COLUMN_MAP.map { |db, col| [db, row[col]] }] attrs = Hash[ABBREV_COLUMN_MAP.map { |db, col| [db, row[col]] }]
lookup = food_data_lookup[attrs[:ndbn]]
if lookup
extra_attrs = Hash[FOOD_DATA_COLUMN_MAP.map { |db, col| [db, lookup[col]] }]
attrs.merge!(extra_attrs)
end
attrs
end end
UsdaFood.create(attributes) UsdaFood.create(attributes)
@ -111,8 +148,8 @@ class UsdaImporter
end end
def csv_options def csv_options(headers)
{ col_sep: '^', quote_char: '~', headers: COLUMNS } { col_sep: '^', quote_char: '~', headers: headers }
end end
end end

View File

@ -5,6 +5,7 @@ FactoryGirl.define do
end end
factory :usda_food do factory :usda_food do
long_description 'Food'
short_description 'Food' short_description 'Food'
ndbn '01234' ndbn '01234'
water 1.0 water 1.0

View File

@ -4,11 +4,11 @@ RSpec.describe UsdaFood do
let!(:data) do let!(:data) do
{ {
salted_butter: create(:usda_food, short_description: 'Salted Butter'), salted_butter: create(:usda_food, long_description: 'Salted Butter'),
unsalted_butter: create(:usda_food, short_description: 'Unsalted Butter'), unsalted_butter: create(:usda_food, long_description: 'Unsalted Butter'),
flour: create(:usda_food, short_description: 'Flour'), flour: create(:usda_food, long_description: 'Flour'),
bread_flour: create(:usda_food, short_description: 'Bread Flour'), bread_flour: create(:usda_food, long_description: 'Bread Flour'),
sugar: create(:usda_food, short_description: 'Sugar,Granulated') sugar: create(:usda_food, long_description: 'Sugar,Granulated')
} }
end end
@ -17,23 +17,23 @@ RSpec.describe UsdaFood do
end end
it 'can be found by single tokens' do it 'can be found by single tokens' do
r = UsdaFood.matches_tokens(:short_description, ['sal']) r = UsdaFood.matches_tokens(:long_description, ['sal'])
expect(r.length).to eq 1 expect(r.length).to eq 1
expect(r).to contain_exactly *items(:salted_butter) expect(r).to contain_exactly *items(:salted_butter)
r = UsdaFood.matches_tokens(:short_description, ['flour']) r = UsdaFood.matches_tokens(:long_description, ['flour'])
expect(r.length).to eq 2 expect(r.length).to eq 2
expect(r).to contain_exactly *items(:flour, :bread_flour) expect(r).to contain_exactly *items(:flour, :bread_flour)
end end
it 'can be found by multiple tokens' do it 'can be found by multiple tokens' do
r = UsdaFood.matches_tokens(:short_description, ['sal', 'butter']) r = UsdaFood.matches_tokens(:long_description, ['sal', 'butter'])
expect(r.length).to eq 1 expect(r.length).to eq 1
expect(r).to contain_exactly *items(:salted_butter) expect(r).to contain_exactly *items(:salted_butter)
end end
it 'treats commas like spaces' do it 'treats commas like spaces' do
r = UsdaFood.matches_tokens(:short_description, ['gran', 'sugar']) r = UsdaFood.matches_tokens(:long_description, ['gran', 'sugar'])
expect(r.length).to eq 1 expect(r.length).to eq 1
expect(r).to contain_exactly *items(:sugar) expect(r).to contain_exactly *items(:sugar)
end end

8789
vendor/data/usda/FOOD_DES.txt vendored Normal file

File diff suppressed because it is too large Load Diff