ingredient linking

This commit is contained in:
Dan Elbert 2016-01-24 19:06:26 -06:00
parent 9f04a65e19
commit 7f7a81d49a
11 changed files with 258 additions and 32 deletions

View File

@ -0,0 +1,43 @@
(function($) {
var usdaFoodSearchEngine = new Bloodhound({
initialize: false,
datumTokenizer: function(datum) {
return Bloodhound.tokenizers.whitespace(datum.name);
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
identify: function(datum) { return datum.ndbn; },
sorter: function(a, b) {
if (a.name < b.name) {
return -1;
} else if (b.name < a.name) {
return 1;
} else {
return 0;
}
},
remote: {
url: '/ingredients/usda_food_search.json?query=%QUERY',
wildcard: '%QUERY'
}
});
$(document).on("ready page:load", function() {
var $ingredientForm = $("#ingredient_form");
if ($ingredientForm.length) {
usdaFoodSearchEngine.initialize(false);
}
$ingredientForm.find(".ndbn_typeahead").typeahead_selector({
},{
name: 'usdaFoods',
source: usdaFoodSearchEngine,
display: function(datum) {
return datum.name;
}
});
});
})(jQuery);

View File

@ -1,5 +1,31 @@
(function($) {
var ingredientSearchEngine = new Bloodhound({
initialize: false,
datumTokenizer: function(datum) {
return Bloodhound.tokenizers.whitespace(datum.name);
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
identify: function(datum) { return datum.id; },
sorter: function(a, b) {
if (a.name < b.name) {
return -1;
} else if (b.name < a.name) {
return 1;
} else {
return 0;
}
},
prefetch: {
url: '/ingredients/prefetch.json',
cache: false
},
remote: {
url: '/ingredients/search.json?query=%QUERY',
wildcard: '%QUERY'
}
});
function reorder($container) {
$container.find("div.nested-fields").each(function(idx, editor) {
var $editor = $(editor);
@ -104,33 +130,13 @@
$(document).on("ready page:load", function() {
var ingredientSearchEngine = new Bloodhound({
datumTokenizer: function(datum) {
return Bloodhound.tokenizers.whitespace(datum.name);
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
identify: function(datum) { return datum.id; },
sorter: function(a, b) {
if (a.name < b.name) {
return -1;
} else if (b.name < a.name) {
return 1;
} else {
return 0;
}
},
prefetch: {
url: '/ingredients/prefetch.json',
cache: false
},
remote: {
url: '/ingredients/search.json?query=%QUERY',
wildcard: '%QUERY'
}
});
var $ingredientList = $("#ingredient-list");
var $stepList = $("#step-list");
if ($ingredientList.length) {
ingredientSearchEngine.initialize(false);
}
initializeStepEditor($stepList);
$stepList
@ -147,7 +153,6 @@
$span.html($this.val());
});
var $ingredientList = $("#ingredient-list");
initializeIngredientEditor($ingredientList, ingredientSearchEngine);

View File

@ -0,0 +1,70 @@
(function($) {
var pluginName = "typeahead_selector";
var defaultOptions = {
};
var methods = {
initialize: function (opts, sources) {
return this.each(function() {
var options = $.extend({}, defaultOptions, opts);
var $this = $(this);
$this.typeahead(opts, sources);
$this
.on("typeahead:change", function(evt, value) {
privateMethods.change($this, value);
})
.on("typeahead:select", function(evt, value) {
privateMethods.select($this, value);
})
.on("typeahead:autocomplete", function(evt, value) {
privateMethods.autocomplete($this, value);
});
});
},
val: function() {
if (this.length) {
return $(this[0]).data('typeahead_selected');
} else {
return null;
}
}
};
var privateMethods = {
change: function($this, value) {
var item = $this.data('typeahead_pending');
if (item) {
$this.data('typeahead_pending', null);
$this.data('typeahead_selected', item);
$this.trigger("typeahead_selector:selected", item);
} else {
$this.data('typeahead_selected', null);
$this.trigger("typeahead_selector:invalid", value);
}
},
select: function($this, item) {
$this.data('typeahead_pending', item);
},
autocomplete: function($this, item) {
$this.data('typeahead_pending', item);
}
};
$.fn[pluginName] = function (method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || ! method) {
return methods.initialize.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.' + pluginName);
}
};
})(jQuery);

View File

@ -80,6 +80,10 @@ class IngredientsController < ApplicationController
end
end
def usda_food_search
@foods = UsdaFood.where("short_description LIKE ?", "%#{params[:query]}%").limit(50)
end
private
# Use callbacks to share common setup or constraints between actions.
def set_ingredient

View File

@ -5,6 +5,13 @@ class Ingredient < ActiveRecord::Base
def set_usda_food(food)
self.ndbn = food.ndbn
self.water = food.water
self.protein = food.protein
self.lipids = food.lipid
self.ash = food.ash
self.kcal = food.kcal
self.fiber = food.fiber
self.sugar = food.sugar
self.density = calculate_density(food.gram_weight_1, food.gram_weight_desc_1) || calculate_density(food.gram_weight_2, food.gram_weight_desc_2)
end

View File

@ -1,6 +1,6 @@
<%= form_for(@ingredient) do |f| %>
<%= form_for(@ingredient, html: {id: 'ingredient_form'}) do |f| %>
<%= render partial: 'shared/error_list', locals: {model: @ingredient} %>
@ -9,6 +9,47 @@
<%= f.text_field :name, class: 'form-control', autofocus: true %>
</div>
<div class="form-group">
<%= f.label :ndbn, "Nutrient Databank Number", class: 'control-label' %>
<button type="button" class="btn btn-default" data-toggle="modal" data-target="#link_ndbn_modal">
<span class="glyphicon glyphicon-link"></span><span class="ndbn"><%= @ingredient.ndbn %></span>
</button>
</div>
<fieldset>
<legend>Per 100 Grams</legend>
<div class="form-group">
<%= f.label :water, "Grams of Water", class: 'control-label' %>
<%= f.text_field :water, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :protein, "Grams of Protein", class: 'control-label' %>
<%= f.text_field :protein, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :lipids, "Grams of Fat", class: 'control-label' %>
<%= f.text_field :lipids, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :kcal, "Calories", class: 'control-label' %>
<%= f.text_field :kcal, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :fiber, "Grams of Fiber", class: 'control-label' %>
<%= f.text_field :fiber, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :sugar, "Grams of Sugar", class: 'control-label' %>
<%= f.text_field :sugar, class: 'form-control' %>
</div>
</fieldset>
<div class="form-group">
<%= f.label :density, class: 'control-label' %>
<%= f.text_field :density, class: 'form-control' %>
@ -22,5 +63,30 @@
<div class="actions">
<%= f.submit class: 'btn btn-primary' %>
</div>
<% end %>
<div class="modal fade" id="link_ndbn_modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">USDA Food Link</h4>
</div>
<div class="modal-body">
<div class="form-group">
<%= f.label :ndbn, "", class: 'control-label' %>
<input type="text" class="ndbn_typeahead form-control" />
<%= f.hidden_field :ndbn %>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary" form="conversion_form">Link</button>
</div>
</div>
</div>
</div>
<% end %>

View File

@ -0,0 +1,7 @@
json.array! @foods do |f|
json.extract! f, :ndbn
json.name f.short_description
end

View File

@ -12,6 +12,7 @@ Rails.application.routes.draw do
get :search
get :prefetch
get :convert
get :usda_food_search
end
end
end

View File

@ -0,0 +1,15 @@
class AddFieldsToIngredient < ActiveRecord::Migration
def change
change_table :ingredients do |t|
t.decimal :water, precision: 10, scale: 2
t.decimal :protein, precision: 10, scale: 2
t.decimal :lipids, precision: 10, scale: 2
t.decimal :ash, precision: 10, scale: 2
t.decimal :carbohydrates, precision: 10, scale: 2
t.integer :kcal
t.decimal :fiber, precision: 10, scale: 1
t.decimal :sugar, precision: 10, scale: 2
end
end
end

View File

@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160124222409) do
ActiveRecord::Schema.define(version: 20160124231837) do
create_table "ingredients", force: :cascade do |t|
t.string "name"
@ -20,6 +20,14 @@ ActiveRecord::Schema.define(version: 20160124222409) do
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "ndbn", limit: 5
t.decimal "water", precision: 10, scale: 2
t.decimal "protein", precision: 10, scale: 2
t.decimal "lipids", precision: 10, scale: 2
t.decimal "ash", precision: 10, scale: 2
t.decimal "carbohydrates", precision: 10, scale: 2
t.integer "kcal"
t.decimal "fiber", precision: 10, scale: 1
t.decimal "sugar", precision: 10, scale: 2
end
create_table "recipe_ingredients", force: :cascade do |t|

0
lib/tasks/usda.rake Normal file
View File