updates
This commit is contained in:
parent
ffed63e0b3
commit
0c4c5b899b
@ -7,12 +7,19 @@ class CalculatorController < ApplicationController
|
|||||||
def calculate
|
def calculate
|
||||||
input = params[:input]
|
input = params[:input]
|
||||||
output_unit = params[:output_unit]
|
output_unit = params[:output_unit]
|
||||||
|
ingredient_id = params[:ingredient_id]
|
||||||
|
ingredient = nil
|
||||||
density = params[:density]
|
density = params[:density]
|
||||||
density = nil unless density.present?
|
density = nil unless density.present?
|
||||||
|
|
||||||
|
if ingredient_id.present?
|
||||||
|
ingredient = Ingredient.find_by_ingredient_id(ingredient_id)
|
||||||
|
end
|
||||||
|
|
||||||
data = {errors: [], output: ''}
|
data = {errors: [], output: ''}
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
UnitConversion::with_custom_units(ingredient ? ingredient.custom_units : []) do
|
||||||
unit = UnitConversion.parse(input)
|
unit = UnitConversion.parse(input)
|
||||||
if output_unit.present?
|
if output_unit.present?
|
||||||
unit = unit.convert(output_unit, density)
|
unit = unit.convert(output_unit, density)
|
||||||
@ -20,7 +27,7 @@ class CalculatorController < ApplicationController
|
|||||||
else
|
else
|
||||||
data[:output] = unit.auto_unit.to_s
|
data[:output] = unit.auto_unit.to_s
|
||||||
end
|
end
|
||||||
|
end
|
||||||
rescue UnitConversion::UnparseableUnitError => e
|
rescue UnitConversion::UnparseableUnitError => e
|
||||||
data[:errors] << e.message
|
data[:errors] << e.message
|
||||||
end
|
end
|
||||||
|
@ -61,12 +61,12 @@ class LogsController < ApplicationController
|
|||||||
private
|
private
|
||||||
|
|
||||||
def set_log
|
def set_log
|
||||||
@log = Log.includes({recipe: {recipe_ingredients: {ingredient: :ingredient_units} }}).find(params[:id])
|
@log = Log.includes({recipe: {recipe_ingredients: {food: :food_units} }}).find(params[:id])
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_recipe
|
def set_recipe
|
||||||
if params[:recipe_id].present?
|
if params[:recipe_id].present?
|
||||||
@recipe = Recipe.includes([{recipe_ingredients: [:ingredient]}]).find(params[:recipe_id])
|
@recipe = Recipe.includes([{recipe_ingredients: [:food]}]).find(params[:recipe_id])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ class RecipesController < ApplicationController
|
|||||||
private
|
private
|
||||||
# Use callbacks to share common setup or constraints between actions.
|
# Use callbacks to share common setup or constraints between actions.
|
||||||
def set_recipe
|
def set_recipe
|
||||||
@recipe = Recipe.includes(recipe_ingredients: {food: :food_units }).find(params[:id])
|
@recipe = Recipe.includes(recipe_ingredients: [{food: :food_units }, {recipe_as_ingredient: {recipe_ingredients: {food: :food_units }}}]).find(params[:id])
|
||||||
end
|
end
|
||||||
|
|
||||||
# Never trust parameters from the scary internet, only allow the white list through.
|
# Never trust parameters from the scary internet, only allow the white list through.
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<span ref="wrapper" class="rating" @click="handleClick" @mousemove="handleMousemove" @mouseleave="handleMouseleave">
|
<span ref="wrapper" class="rating" @click="handleClick" @mousemove="handleMousemove" @mouseleave="handleMouseleave">
|
||||||
<span class="set empty-set">
|
<span class="set empty-set">
|
||||||
<app-icon v-for="i in starCount" :key="i" icon="star-empty" padding="0"></app-icon>
|
<app-iconic-icon v-for="i in starCount" :key="i" icon="star-empty" size="md"></app-iconic-icon>
|
||||||
</span>
|
</span>
|
||||||
<span class="set filled-set" :style="filledStyle">
|
<span class="set filled-set" :style="filledStyle">
|
||||||
<app-icon v-for="i in starCount" :key="i" icon="star" padding="0"></app-icon>
|
<app-iconic-icon v-for="i in starCount" :key="i" icon="star" size="md"></app-iconic-icon>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
@ -113,6 +113,11 @@
|
|||||||
|
|
||||||
.set {
|
.set {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
||||||
|
svg.iconic {
|
||||||
|
width: 1.5em;
|
||||||
|
height: 1.5em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-set {
|
.empty-set {
|
||||||
|
@ -10,10 +10,6 @@
|
|||||||
<div class="column">
|
<div class="column">
|
||||||
<app-text-field label="Source" v-model="recipe.source"></app-text-field>
|
<app-text-field label="Source" v-model="recipe.source"></app-text-field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="column">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<app-text-field label="Description" type="textarea" v-model="recipe.description"></app-text-field>
|
<app-text-field label="Description" type="textarea" v-model="recipe.description"></app-text-field>
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
|
||||||
|
<transition-group tag="tbody" name="list-item-move">
|
||||||
<tr v-for="i in taskItems" :key="i.id" @click="toggleItem(i)">
|
<tr v-for="i in taskItems" :key="i.id" @click="toggleItem(i)">
|
||||||
<td>
|
<td>
|
||||||
<div class="check">
|
<div class="check">
|
||||||
@ -28,7 +29,9 @@
|
|||||||
<td>{{ i.quantity }}</td>
|
<td>{{ i.quantity }}</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-if="taskItems.length === 0">
|
</transition-group>
|
||||||
|
<tbody v-if="taskItems.length === 0">
|
||||||
|
<tr>
|
||||||
<td colspan="4">
|
<td colspan="4">
|
||||||
No Items
|
No Items
|
||||||
</td>
|
</td>
|
||||||
@ -73,20 +76,16 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
completedTaskItems() {
|
||||||
|
return (this.taskList ? this.taskList.task_items : []).filter(i => i.completed);
|
||||||
|
},
|
||||||
|
|
||||||
|
uncompletedTaskItems() {
|
||||||
|
return (this.taskList ? this.taskList.task_items : []).filter(i => !i.completed);
|
||||||
|
},
|
||||||
|
|
||||||
taskItems() {
|
taskItems() {
|
||||||
const top = [];
|
return this.uncompletedTaskItems.concat(this.completedTaskItems);
|
||||||
const bottom = [];
|
|
||||||
const list = (this.taskList ? this.taskList.task_items : []);
|
|
||||||
|
|
||||||
for (let i of list) {
|
|
||||||
if (!i.completed) {
|
|
||||||
top.push(i);
|
|
||||||
} else {
|
|
||||||
bottom.push(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return top.concat(bottom);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -148,8 +147,9 @@
|
|||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.check .icon {
|
div.check {
|
||||||
border: 2px solid $link;
|
border: 2px solid $link;
|
||||||
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
@ -44,7 +44,7 @@
|
|||||||
<div class="field column">
|
<div class="field column">
|
||||||
<label class="label">Density</label>
|
<label class="label">Density</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<input class="input" type="text" placeholder="8.345 lb/gallon" v-model="density">
|
<input class="input" type="text" placeholder="8.345 lb/gallon" v-model="density" :disabled="ingredient !== null">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -82,13 +82,13 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
searchItemSelected(ingredient) {
|
searchItemSelected(ingredient) {
|
||||||
this.ingredient = ingredient;
|
this.ingredient = ingredient || null;
|
||||||
this.ingredient_name = ingredient.name;
|
this.ingredient_name = ingredient.name || null;
|
||||||
this.density = ingredient.density;
|
this.density = ingredient.density || null;
|
||||||
},
|
},
|
||||||
|
|
||||||
updateOutput: debounce(function() {
|
updateOutput: debounce(function() {
|
||||||
this.loadResource(api.getCalculate(this.input, this.outputUnit, this.density)
|
this.loadResource(api.getCalculate(this.input, this.outputUnit, this.ingredient ? this.ingredient.ingredient_id : null, this.density)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
this.output = data.output;
|
this.output = data.output;
|
||||||
this.errors = data.errors;
|
this.errors = data.errors;
|
||||||
@ -108,7 +108,7 @@
|
|||||||
created() {
|
created() {
|
||||||
this.$watch(
|
this.$watch(
|
||||||
function() {
|
function() {
|
||||||
return this.input + this.outputUnit + this.density;
|
return [this.input, this.outputUnit, this.density, this.ingredient];
|
||||||
},
|
},
|
||||||
function() {
|
function() {
|
||||||
this.updateOutput();
|
this.updateOutput();
|
||||||
|
@ -16,9 +16,9 @@
|
|||||||
<div v-if="currentTaskList !== null">
|
<div v-if="currentTaskList !== null">
|
||||||
|
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<button class="button" @click="deleteCompletedItems">Clear Completed</button>
|
<button class="button" @click="deleteCompletedItems" v-if="completedItemCount > 0">Clear Completed</button>
|
||||||
<button class="button" @click="completeAllItems">Check All</button>
|
<button class="button" @click="completeAllItems" v-if="uncompletedItemCount > 0">Check All</button>
|
||||||
<button class="button" @click="unCompleteAllItems">Uncheck All</button>
|
<button class="button" @click="unCompleteAllItems" v-if="completedItemCount > 0">Uncheck All</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="box">
|
<div class="box">
|
||||||
@ -66,6 +66,14 @@
|
|||||||
} else {
|
} else {
|
||||||
return this.currentTaskList.name;
|
return this.currentTaskList.name;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
completedItemCount() {
|
||||||
|
return this.currentTaskList === null ? 0 : this.currentTaskList.task_items.filter(i => i.completed).length;
|
||||||
|
},
|
||||||
|
|
||||||
|
uncompletedItemCount() {
|
||||||
|
return this.currentTaskList === null ? 0 : this.currentTaskList.task_items.filter(i => !i.completed).length;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -205,10 +205,11 @@ class Api {
|
|||||||
return this.get("/ingredients/search", params);
|
return this.get("/ingredients/search", params);
|
||||||
}
|
}
|
||||||
|
|
||||||
getCalculate(input, output_unit, density) {
|
getCalculate(input, output_unit, ingredient_id, density) {
|
||||||
const params = {
|
const params = {
|
||||||
input,
|
input,
|
||||||
output_unit,
|
output_unit,
|
||||||
|
ingredient_id,
|
||||||
density
|
density
|
||||||
};
|
};
|
||||||
return this.get("/calculator/calculate", params);
|
return this.get("/calculator/calculate", params);
|
||||||
|
@ -15,7 +15,8 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
//.expand-enter,
|
|
||||||
//.expand-leave-to {
|
|
||||||
// height: 0;
|
.list-item-move-move {
|
||||||
//}
|
transition: transform 0.25s;
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
class Food < ApplicationRecord
|
class Food < Ingredient
|
||||||
include TokenizedLike
|
include TokenizedLike
|
||||||
|
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
@ -33,18 +33,10 @@ class Food < ApplicationRecord
|
|||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
def nutrition_errors
|
|
||||||
[]
|
|
||||||
end
|
|
||||||
|
|
||||||
def nutrition_unit
|
def nutrition_unit
|
||||||
UnitConversion.parse('100 grams')
|
UnitConversion.parse('100 grams')
|
||||||
end
|
end
|
||||||
|
|
||||||
def density?
|
|
||||||
!density.nil?
|
|
||||||
end
|
|
||||||
|
|
||||||
def ndbn=(value)
|
def ndbn=(value)
|
||||||
@usda_food = nil
|
@usda_food = nil
|
||||||
super
|
super
|
||||||
|
41
app/models/ingredient.rb
Normal file
41
app/models/ingredient.rb
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
class Ingredient < ApplicationRecord
|
||||||
|
self.abstract_class = true
|
||||||
|
|
||||||
|
class << self
|
||||||
|
|
||||||
|
def find_by_ingredient_id(ingredient_id)
|
||||||
|
puts "looking up |#{ingredient_id}|"
|
||||||
|
case ingredient_id
|
||||||
|
when /^R(\d+)$/
|
||||||
|
puts 'rec'
|
||||||
|
Recipe.find($1)
|
||||||
|
when /^F(\d+)$/
|
||||||
|
puts 'food'
|
||||||
|
Food.find($1)
|
||||||
|
else
|
||||||
|
raise ActiveRecord::RecordNotFound
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def ingredient_id
|
||||||
|
case self
|
||||||
|
when Recipe
|
||||||
|
"R#{id}"
|
||||||
|
when Food
|
||||||
|
"F#{id}"
|
||||||
|
else
|
||||||
|
raise 'Unknown ingredient'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def nutrition_errors
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
|
||||||
|
def density?
|
||||||
|
!self.density.nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
@ -50,7 +50,7 @@ class NutritionData
|
|||||||
end
|
end
|
||||||
|
|
||||||
unless i.ingredient.nutrition_errors.empty?
|
unless i.ingredient.nutrition_errors.empty?
|
||||||
@errors << "#{i.name} has errors: #{i.ingredient.nutrition_errors.join(", ")}"
|
@errors << "#{i.name}: #{i.ingredient.nutrition_errors.join(", ")}"
|
||||||
end
|
end
|
||||||
|
|
||||||
missing = []
|
missing = []
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
class Recipe < ApplicationRecord
|
class Recipe < Ingredient
|
||||||
include DefaultValues
|
include DefaultValues
|
||||||
include TokenizedLike
|
include TokenizedLike
|
||||||
|
|
||||||
@ -157,10 +157,6 @@ class Recipe < ApplicationRecord
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def density?
|
|
||||||
!density.nil?
|
|
||||||
end
|
|
||||||
|
|
||||||
def custom_units
|
def custom_units
|
||||||
arbitrary = self.yields_list.select { |y| !y.mass? && !y.volume? }
|
arbitrary = self.yields_list.select { |y| !y.mass? && !y.volume? }
|
||||||
mass = self.yields_list.select { |y| y.mass? }
|
mass = self.yields_list.select { |y| y.mass? }
|
||||||
|
@ -1,15 +1,7 @@
|
|||||||
|
|
||||||
json.array! @ingredients do |i|
|
json.array! @ingredients do |i|
|
||||||
|
|
||||||
json.extract! i, :name
|
json.extract! i, :ingredient_id, :name, :density
|
||||||
|
json.id i.ingredient_id
|
||||||
case i
|
|
||||||
when Recipe
|
|
||||||
json.id "R#{i.id}"
|
|
||||||
when Food
|
|
||||||
json.id "F#{i.id}"
|
|
||||||
else
|
|
||||||
json.id nil
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
28
db/seeds.rb
28
db/seeds.rb
@ -12,7 +12,7 @@ puts "Seeding..."
|
|||||||
|
|
||||||
dan = User.create!({username: 'dan', full_name: 'Dan', email: 'dan.elbert@gmail.com', password: 'qwerty', password_confirmation: 'qwerty'})
|
dan = User.create!({username: 'dan', full_name: 'Dan', email: 'dan.elbert@gmail.com', password: 'qwerty', password_confirmation: 'qwerty'})
|
||||||
|
|
||||||
ingredients = {
|
foods = {
|
||||||
water: {name: 'Water', density: '1 g/ml'},
|
water: {name: 'Water', density: '1 g/ml'},
|
||||||
butter: {name: 'Butter, Salted', ndbn: '01001'},
|
butter: {name: 'Butter, Salted', ndbn: '01001'},
|
||||||
butter_sal: {name: 'Butter, Unsalted', density: '226 gram/cup'},
|
butter_sal: {name: 'Butter, Unsalted', density: '226 gram/cup'},
|
||||||
@ -43,8 +43,8 @@ ingredients = {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ingredients.each do |k, v|
|
foods.each do |k, v|
|
||||||
ingredients[k] = Food.create!({user_id: dan.id}.merge(v))
|
foods[k] = Food.create!({user_id: dan.id}.merge(v))
|
||||||
end
|
end
|
||||||
|
|
||||||
g = Recipe.create!({
|
g = Recipe.create!({
|
||||||
@ -69,19 +69,19 @@ bb = Recipe.create!({
|
|||||||
bb.tag_names = ['beef', 'dinner', 'stirfry']
|
bb.tag_names = ['beef', 'dinner', 'stirfry']
|
||||||
|
|
||||||
[
|
[
|
||||||
{quantity: '1', units: 'pound', preparation: 'flank steak, skirt steak, hanger steak, or flap meat, cut into 1/4-inch thick strips', food: ingredients[:flank]},
|
{quantity: '1', units: 'pound', preparation: 'flank steak, skirt steak, hanger steak, or flap meat, cut into 1/4-inch thick strips', food: foods[:flank]},
|
||||||
{quantity: '1/4', units: 'cup', preparation: 'divided', food: ingredients[:soy_sauce]},
|
{quantity: '1/4', units: 'cup', preparation: 'divided', food: foods[:soy_sauce]},
|
||||||
{quantity: '1/4', units: 'cup', preparation: 'divided', food: ingredients[:shaoxing]},
|
{quantity: '1/4', units: 'cup', preparation: 'divided', food: foods[:shaoxing]},
|
||||||
{quantity: '2', units: 'teaspoons', preparation: '', food: ingredients[:cornstarch]},
|
{quantity: '2', units: 'teaspoons', preparation: '', food: foods[:cornstarch]},
|
||||||
{quantity: '1/3', units: 'cup', preparation: '', food: ingredients[:stock]},
|
{quantity: '1/3', units: 'cup', preparation: '', food: foods[:stock]},
|
||||||
{quantity: '1/4', units: 'cup', preparation: '', food: ingredients[:oyster_sauce]},
|
{quantity: '1/4', units: 'cup', preparation: '', food: foods[:oyster_sauce]},
|
||||||
{quantity: '1', units: 'tablespoon', preparation: '', food: ingredients[:sugar]},
|
{quantity: '1', units: 'tablespoon', preparation: '', food: foods[:sugar]},
|
||||||
{quantity: '1', units: 'teaspoon', preparation: '', food: ingredients[:seasame_oil]},
|
{quantity: '1', units: 'teaspoon', preparation: '', food: foods[:seasame_oil]},
|
||||||
{quantity: '2', units: 'medium cloves', preparation: 'finely minced', food: ingredients[:garlic]},
|
{quantity: '2', units: 'medium cloves', preparation: 'finely minced', food: foods[:garlic]},
|
||||||
{quantity: '2', units: 'teaspoons', preparation: 'finely minced', name: 'ginger root'},
|
{quantity: '2', units: 'teaspoons', preparation: 'finely minced', name: 'ginger root'},
|
||||||
{quantity: '3', units: '', preparation: 'whites finely sliced, greens cut into 1/2-inch segments, reserved separately', name: 'Scallions'},
|
{quantity: '3', units: '', preparation: 'whites finely sliced, greens cut into 1/2-inch segments, reserved separately', name: 'Scallions'},
|
||||||
{quantity: '4', units: 'tablespoons', preparation: '', food: ingredients[:peanut_oil]},
|
{quantity: '4', units: 'tablespoons', preparation: '', food: foods[:peanut_oil]},
|
||||||
{quantity: '1', units: 'pound', preparation: '', food: ingredients[:broccoli]},
|
{quantity: '1', units: 'pound', preparation: '', food: foods[:broccoli]},
|
||||||
].each_with_index do |ri, i|
|
].each_with_index do |ri, i|
|
||||||
RecipeIngredient.create!({recipe: bb, sort_order: i}.merge(ri))
|
RecipeIngredient.create!({recipe: bb, sort_order: i}.merge(ri))
|
||||||
end
|
end
|
||||||
|
@ -20,7 +20,9 @@ module Unitwise
|
|||||||
def self.with_custom_units(unit_list, &block)
|
def self.with_custom_units(unit_list, &block)
|
||||||
|
|
||||||
atoms = []
|
atoms = []
|
||||||
|
ret_val = nil
|
||||||
|
|
||||||
|
begin
|
||||||
unit_list.each do |u|
|
unit_list.each do |u|
|
||||||
atom = Unitwise::Atom.new(u)
|
atom = Unitwise::Atom.new(u)
|
||||||
atom.validate!
|
atom.validate!
|
||||||
@ -30,13 +32,14 @@ module Unitwise
|
|||||||
rem = Unitwise::Expression::Decomposer.send(:reset)
|
rem = Unitwise::Expression::Decomposer.send(:reset)
|
||||||
|
|
||||||
ret_val = block.call
|
ret_val = block.call
|
||||||
|
ensure
|
||||||
atoms.each do |a|
|
atoms.each do |a|
|
||||||
idx = Unitwise::Atom.all.index { |b| b.equal?(a) }
|
idx = Unitwise::Atom.all.index { |b| b.equal?(a) }
|
||||||
Unitwise::Atom.all.delete_at(idx)
|
Unitwise::Atom.all.delete_at(idx)
|
||||||
# Unitwise::Atom.all.pop
|
# Unitwise::Atom.all.pop
|
||||||
end
|
end
|
||||||
Unitwise::Expression::Decomposer.send(:reset, rem)
|
Unitwise::Expression::Decomposer.send(:reset, rem)
|
||||||
|
end
|
||||||
|
|
||||||
ret_val
|
ret_val
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user