recipe as ingredient work
This commit is contained in:
parent
a6cf7c1b16
commit
56fe5aae35
@ -29,7 +29,7 @@ class CalculatorController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def ingredient_search
|
def ingredient_search
|
||||||
@ingredients = Ingredient.has_density.search(params[:query]).order(:name)
|
@foods = Food.has_density.search(params[:query]).order(:name)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
141
app/controllers/foods_controller.rb
Normal file
141
app/controllers/foods_controller.rb
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
class FoodsController < ApplicationController
|
||||||
|
|
||||||
|
before_action :set_food, only: [:show, :edit, :update, :destroy]
|
||||||
|
|
||||||
|
before_action :ensure_valid_user, except: [:index, :show]
|
||||||
|
|
||||||
|
# GET /foods
|
||||||
|
# GET /foods.json
|
||||||
|
def index
|
||||||
|
@foods = Food.all.order(:name).page(params[:page]).per(params[:per])
|
||||||
|
if params[:name].present?
|
||||||
|
@foods = @foods.matches_tokens(:name, params[:name].split.take(4))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /foods/new
|
||||||
|
def new
|
||||||
|
@food = Food.new
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /foods/1/edit
|
||||||
|
def edit
|
||||||
|
ensure_owner @food
|
||||||
|
end
|
||||||
|
|
||||||
|
# POST /foods
|
||||||
|
# POST /foods.json
|
||||||
|
def create
|
||||||
|
@food = Food.new(food_params)
|
||||||
|
@food.user = current_user
|
||||||
|
if @food.ndbn.present?
|
||||||
|
@food.set_usda_food(UsdaFood.find_by_ndbn(@food.ndbn))
|
||||||
|
end
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
if @food.save
|
||||||
|
format.html { redirect_to foods_path, notice: 'Ingredient was successfully created.' }
|
||||||
|
format.json { render json: { success: true }, status: :created, location: @food }
|
||||||
|
else
|
||||||
|
format.html { render :new }
|
||||||
|
format.json { render json: @food.errors, status: :unprocessable_entity }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# PATCH/PUT /foods/1
|
||||||
|
def update
|
||||||
|
ensure_owner @food do
|
||||||
|
@food.assign_attributes(food_params)
|
||||||
|
if @food.ndbn.present?
|
||||||
|
@food.set_usda_food(UsdaFood.find_by_ndbn(@food.ndbn))
|
||||||
|
end
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
if @food.save
|
||||||
|
format.html { redirect_to foods_path, notice: 'Ingredient was successfully updated.' }
|
||||||
|
format.json { render json: { success: true }, status: :ok, location: @food }
|
||||||
|
else
|
||||||
|
format.html { render :edit }
|
||||||
|
format.json { render json: @food.errors, status: :unprocessable_entity }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# DELETE /foods/1
|
||||||
|
# DELETE /foods/1.json
|
||||||
|
def destroy
|
||||||
|
ensure_owner @food do
|
||||||
|
@food.destroy
|
||||||
|
respond_to do |format|
|
||||||
|
format.html { redirect_to foods_url, notice: 'Ingredient was successfully destroyed.' }
|
||||||
|
format.json { head :no_content }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def select_ndbn
|
||||||
|
if params[:id].present?
|
||||||
|
@food = Food.find(params[:id])
|
||||||
|
else
|
||||||
|
@food = Food.new
|
||||||
|
end
|
||||||
|
|
||||||
|
@food.assign_attributes(food_params)
|
||||||
|
|
||||||
|
if @food.ndbn.present?
|
||||||
|
@food.set_usda_food(UsdaFood.find_by_ndbn(@food.ndbn))
|
||||||
|
end
|
||||||
|
|
||||||
|
render :show
|
||||||
|
end
|
||||||
|
|
||||||
|
def prefetch
|
||||||
|
@foods = Food.all.order(:name)
|
||||||
|
render :search
|
||||||
|
end
|
||||||
|
|
||||||
|
def search
|
||||||
|
@foods = Food.search(params[:query]).order(:name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def convert
|
||||||
|
@conversion = Conversion.new(conversion_params)
|
||||||
|
|
||||||
|
if @conversion.valid?
|
||||||
|
@output_quantity = @conversion.output_quantity
|
||||||
|
@conversion = Conversion.new
|
||||||
|
else
|
||||||
|
@output_quantity = ''
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def usda_food_search
|
||||||
|
@foods = UsdaFood.search(params[:query]).limit(250).order(:long_description)
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.html { render :layout => false }
|
||||||
|
format.json { }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
# Use callbacks to share common setup or constraints between actions.
|
||||||
|
def set_food
|
||||||
|
@food = Food.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
# Never trust parameters from the scary internet, only allow the white list through.
|
||||||
|
def food_params
|
||||||
|
params.require(:food).permit(:name, :notes, :ndbn, :density, :water, :protein, :lipids, :carbohydrates, :kcal, :fiber, :sugar, :calcium, :sodium, :vit_k, :ash, :iron, :magnesium, :phosphorus, :potassium, :zinc, :copper, :manganese, :vit_c, :vit_b6, :vit_b12, :vit_a, :vit_e, :vit_d, :cholesterol, :ingredient_units_attributes => [:name, :gram_weight, :id, :_destroy])
|
||||||
|
end
|
||||||
|
|
||||||
|
def conversion_params
|
||||||
|
params.require(:conversion).permit(:input_quantity, :input_units, :scale, :output_units, :ingredient_id)
|
||||||
|
end
|
||||||
|
end
|
@ -1,141 +0,0 @@
|
|||||||
class IngredientsController < ApplicationController
|
|
||||||
|
|
||||||
before_action :set_ingredient, only: [:show, :edit, :update, :destroy]
|
|
||||||
|
|
||||||
before_action :ensure_valid_user, except: [:index, :show]
|
|
||||||
|
|
||||||
# GET /ingredients
|
|
||||||
# GET /ingredients.json
|
|
||||||
def index
|
|
||||||
@ingredients = Ingredient.all.order(:name).page(params[:page]).per(params[:per])
|
|
||||||
if params[:name].present?
|
|
||||||
@ingredients = @ingredients.matches_tokens(:name, params[:name].split.take(4))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def show
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
# GET /ingredients/new
|
|
||||||
def new
|
|
||||||
@ingredient = Ingredient.new
|
|
||||||
end
|
|
||||||
|
|
||||||
# GET /ingredients/1/edit
|
|
||||||
def edit
|
|
||||||
ensure_owner @ingredient
|
|
||||||
end
|
|
||||||
|
|
||||||
# POST /ingredients
|
|
||||||
# POST /ingredients.json
|
|
||||||
def create
|
|
||||||
@ingredient = Ingredient.new(ingredient_params)
|
|
||||||
@ingredient.user = current_user
|
|
||||||
if @ingredient.ndbn.present?
|
|
||||||
@ingredient.set_usda_food(UsdaFood.find_by_ndbn(@ingredient.ndbn))
|
|
||||||
end
|
|
||||||
|
|
||||||
respond_to do |format|
|
|
||||||
if @ingredient.save
|
|
||||||
format.html { redirect_to ingredients_path, notice: 'Ingredient was successfully created.' }
|
|
||||||
format.json { render json: { success: true }, status: :created, location: @ingredient }
|
|
||||||
else
|
|
||||||
format.html { render :new }
|
|
||||||
format.json { render json: @ingredient.errors, status: :unprocessable_entity }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# PATCH/PUT /ingredients/1
|
|
||||||
def update
|
|
||||||
ensure_owner @ingredient do
|
|
||||||
@ingredient.assign_attributes(ingredient_params)
|
|
||||||
if @ingredient.ndbn.present?
|
|
||||||
@ingredient.set_usda_food(UsdaFood.find_by_ndbn(@ingredient.ndbn))
|
|
||||||
end
|
|
||||||
|
|
||||||
respond_to do |format|
|
|
||||||
if @ingredient.save
|
|
||||||
format.html { redirect_to ingredients_path, notice: 'Ingredient was successfully updated.' }
|
|
||||||
format.json { render json: { success: true }, status: :ok, location: @ingredient }
|
|
||||||
else
|
|
||||||
format.html { render :edit }
|
|
||||||
format.json { render json: @ingredient.errors, status: :unprocessable_entity }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# DELETE /ingredients/1
|
|
||||||
# DELETE /ingredients/1.json
|
|
||||||
def destroy
|
|
||||||
ensure_owner @ingredient do
|
|
||||||
@ingredient.destroy
|
|
||||||
respond_to do |format|
|
|
||||||
format.html { redirect_to ingredients_url, notice: 'Ingredient was successfully destroyed.' }
|
|
||||||
format.json { head :no_content }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def select_ndbn
|
|
||||||
if params[:id].present?
|
|
||||||
@ingredient = Ingredient.find(params[:id])
|
|
||||||
else
|
|
||||||
@ingredient = Ingredient.new
|
|
||||||
end
|
|
||||||
|
|
||||||
@ingredient.assign_attributes(ingredient_params)
|
|
||||||
|
|
||||||
if @ingredient.ndbn.present?
|
|
||||||
@ingredient.set_usda_food(UsdaFood.find_by_ndbn(@ingredient.ndbn))
|
|
||||||
end
|
|
||||||
|
|
||||||
render :show
|
|
||||||
end
|
|
||||||
|
|
||||||
def prefetch
|
|
||||||
@ingredients = Ingredient.all.order(:name)
|
|
||||||
render :search
|
|
||||||
end
|
|
||||||
|
|
||||||
def search
|
|
||||||
@ingredients = Ingredient.search(params[:query]).order(:name)
|
|
||||||
end
|
|
||||||
|
|
||||||
def convert
|
|
||||||
@conversion = Conversion.new(conversion_params)
|
|
||||||
|
|
||||||
if @conversion.valid?
|
|
||||||
@output_quantity = @conversion.output_quantity
|
|
||||||
@conversion = Conversion.new
|
|
||||||
else
|
|
||||||
@output_quantity = ''
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def usda_food_search
|
|
||||||
@foods = UsdaFood.search(params[:query]).limit(250).order(:long_description)
|
|
||||||
|
|
||||||
respond_to do |format|
|
|
||||||
format.html { render :layout => false }
|
|
||||||
format.json { }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
# Use callbacks to share common setup or constraints between actions.
|
|
||||||
def set_ingredient
|
|
||||||
@ingredient = Ingredient.find(params[:id])
|
|
||||||
end
|
|
||||||
|
|
||||||
# Never trust parameters from the scary internet, only allow the white list through.
|
|
||||||
def ingredient_params
|
|
||||||
params.require(:ingredient).permit(:name, :notes, :ndbn, :density, :water, :protein, :lipids, :carbohydrates, :kcal, :fiber, :sugar, :calcium, :sodium, :vit_k, :ash, :iron, :magnesium, :phosphorus, :potassium, :zinc, :copper, :manganese, :vit_c, :vit_b6, :vit_b12, :vit_a, :vit_e, :vit_d, :cholesterol, :ingredient_units_attributes => [:name, :gram_weight, :id, :_destroy])
|
|
||||||
end
|
|
||||||
|
|
||||||
def conversion_params
|
|
||||||
params.require(:conversion).permit(:input_quantity, :input_units, :scale, :output_units, :ingredient_id)
|
|
||||||
end
|
|
||||||
end
|
|
4
app/helpers/foods_helper.rb
Normal file
4
app/helpers/foods_helper.rb
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
module FoodsHelper
|
||||||
|
|
||||||
|
|
||||||
|
end
|
@ -1,4 +0,0 @@
|
|||||||
module IngredientsHelper
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
24
app/models/concerns/ingredient.rb
Normal file
24
app/models/concerns/ingredient.rb
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
# Mixin for Ingredient-like things.
|
||||||
|
# Consumer is expected to have the following methods:
|
||||||
|
# #name => name of ingredient
|
||||||
|
# #density => valid density string or nil
|
||||||
|
# #custom_units => map of unit names to a weight (eg { 'clove' => '25 g', 'bulb' => '175 g' })
|
||||||
|
# #nutrition_per_100g => Object that responds to all nutrition keys in NutritionData
|
||||||
|
# nutrition_per_100g_errors => list of errors
|
||||||
|
module Ingredient
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
end
|
||||||
|
|
||||||
|
# Shared helper methods
|
||||||
|
def density?
|
||||||
|
!density.nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module ClassMethods
|
||||||
|
end
|
||||||
|
end
|
@ -21,7 +21,7 @@ class Conversion
|
|||||||
|
|
||||||
def check_conversion
|
def check_conversion
|
||||||
begin
|
begin
|
||||||
ingredient = ingredient_id.blank? ? nil : Ingredient.find(ingredient_id)
|
ingredient = ingredient_id.blank? ? nil : Food.find(ingredient_id)
|
||||||
scale = self.scale.blank? ? '1' : self.scale
|
scale = self.scale.blank? ? '1' : self.scale
|
||||||
density = ingredient.nil? ? nil : ingredient.density
|
density = ingredient.nil? ? nil : ingredient.density
|
||||||
@output_quantity = UnitConversion.convert(input_quantity, scale, input_units, output_units, density)
|
@output_quantity = UnitConversion.convert(input_quantity, scale, input_units, output_units, density)
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
class Ingredient < ApplicationRecord
|
class Food < ApplicationRecord
|
||||||
|
include Ingredient
|
||||||
include TokenizedLike
|
include TokenizedLike
|
||||||
|
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
has_many :ingredient_units, inverse_of: :ingredient, dependent: :destroy
|
has_many :food_units, inverse_of: :food, dependent: :destroy
|
||||||
|
|
||||||
accepts_nested_attributes_for :ingredient_units, allow_destroy: true
|
accepts_nested_attributes_for :food_units, allow_destroy: true
|
||||||
|
|
||||||
validates :name, presence: true
|
validates :name, presence: true
|
||||||
validates :density, density: true, allow_blank: true
|
validates :density, density: true, allow_blank: true
|
||||||
@ -15,20 +16,26 @@ class Ingredient < ApplicationRecord
|
|||||||
tokens = query.to_s.split(' ')
|
tokens = query.to_s.split(' ')
|
||||||
|
|
||||||
if tokens.empty?
|
if tokens.empty?
|
||||||
Ingredient.none
|
Food.none
|
||||||
else
|
else
|
||||||
Ingredient.matches_tokens(:name, tokens)
|
Food.matches_tokens(:name, tokens)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def custom_unit_weight(unit)
|
def custom_units
|
||||||
ingredient_units.each do |iu|
|
units = {}
|
||||||
if iu.matches?(unit)
|
food_units.each do |fu|
|
||||||
return UnitConversion::parse(iu.gram_weight, 'grams')
|
units[fu.name] = UnitConversion::parse(fu.gram_weight, "grams")
|
||||||
end
|
end
|
||||||
|
units
|
||||||
end
|
end
|
||||||
|
|
||||||
nil
|
def nutrition_per_100g
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def nutrition_per_100g_errors
|
||||||
|
[]
|
||||||
end
|
end
|
||||||
|
|
||||||
def ndbn=(value)
|
def ndbn=(value)
|
@ -1,5 +1,5 @@
|
|||||||
class IngredientUnit < ApplicationRecord
|
class FoodUnit < ApplicationRecord
|
||||||
belongs_to :ingredient, inverse_of: :ingredient_units
|
belongs_to :food, inverse_of: :food_units
|
||||||
|
|
||||||
validates :name, presence: true
|
validates :name, presence: true
|
||||||
validates :gram_weight, presence: true
|
validates :gram_weight, presence: true
|
@ -2,24 +2,24 @@ class IngredientProxy
|
|||||||
|
|
||||||
attr_reader :ingredient
|
attr_reader :ingredient
|
||||||
|
|
||||||
def initialize(ingredient)
|
def initialize(food)
|
||||||
@ingredient = ingredient
|
@food = food
|
||||||
end
|
end
|
||||||
|
|
||||||
def name
|
def name
|
||||||
@ingredient.name
|
@food.name
|
||||||
end
|
end
|
||||||
|
|
||||||
def density
|
def density
|
||||||
@ingredient.density
|
@food.density
|
||||||
end
|
end
|
||||||
|
|
||||||
def density?
|
def density?
|
||||||
@ingredient.density.present?
|
@food.density.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_custom_unit_equivalent(custom_unit_name)
|
def get_custom_unit_equivalent(custom_unit_name)
|
||||||
@ingredient.custom_unit_weight(custom_unit_name)
|
@food.custom_unit_weight(custom_unit_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
@ -53,7 +53,7 @@ class NutritionData
|
|||||||
missing = []
|
missing = []
|
||||||
|
|
||||||
NUTRIENTS.each do |k, n|
|
NUTRIENTS.each do |k, n|
|
||||||
value = i.ingredient.send(k)
|
value = i.food.send(k)
|
||||||
if value.present?
|
if value.present?
|
||||||
value = value.to_f
|
value = value.to_f
|
||||||
running_total = self.instance_variable_get("@#{k}".to_sym)
|
running_total = self.instance_variable_get("@#{k}".to_sym)
|
||||||
@ -70,11 +70,6 @@ class NutritionData
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
NUTRIENTS.each do |k, n|
|
|
||||||
v = self.instance_variable_get("@#{k}".to_sym)
|
|
||||||
self.instance_variable_set("@#{k}".to_sym, v.round(2))
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
@ -1,4 +1,5 @@
|
|||||||
class Recipe < ApplicationRecord
|
class Recipe < ApplicationRecord
|
||||||
|
include Ingredient
|
||||||
include TokenizedLike
|
include TokenizedLike
|
||||||
|
|
||||||
has_many :recipe_ingredients, -> { order :sort_order }, inverse_of: :recipe, dependent: :destroy
|
has_many :recipe_ingredients, -> { order :sort_order }, inverse_of: :recipe, dependent: :destroy
|
||||||
@ -71,7 +72,13 @@ class Recipe < ApplicationRecord
|
|||||||
|
|
||||||
def yields_list
|
def yields_list
|
||||||
if self.yields.present?
|
if self.yields.present?
|
||||||
self.yields.split(',').map { |y| y.strip }.select { |y| y.present? }
|
self.yields.split(',').map { |y| y.strip }.select { |y| y.present? }.map do |y|
|
||||||
|
begin
|
||||||
|
UnitConversion::parse(y)
|
||||||
|
rescue UntConversion::UnparseableUnitError
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end.compact
|
||||||
else
|
else
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
@ -123,6 +130,28 @@ class Recipe < ApplicationRecord
|
|||||||
copy
|
copy
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def density
|
||||||
|
mas = yields_list.detect { |y| y.mass? }
|
||||||
|
vol = yields_list.detect { |y| y.volume? }
|
||||||
|
if mas && vol
|
||||||
|
"#{mas.value.value / vol.value.value} #{mas.unit.original_unit}/#{vol.unit.original_unit}"
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def custom_units
|
||||||
|
Hash[yields_list.select { |y| !y.mass? && !y.volume? && y.unit }.map { [y.unit.unit, y] }]
|
||||||
|
end
|
||||||
|
|
||||||
|
def nutrition_per_100g
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def nutrition_per_100g_errors
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
def self.for_criteria(criteria)
|
def self.for_criteria(criteria)
|
||||||
query = active.order(criteria.sort_column => criteria.sort_direction)
|
query = active.order(criteria.sort_column => criteria.sort_direction)
|
||||||
|
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
class RecipeIngredient < ApplicationRecord
|
class RecipeIngredient < ApplicationRecord
|
||||||
|
|
||||||
belongs_to :ingredient, optional: true
|
belongs_to :food, optional: true
|
||||||
belongs_to :recipe_as_ingredient, class_name: 'Recipe', optional: true
|
belongs_to :recipe_as_ingredient, class_name: 'Recipe', optional: true
|
||||||
belongs_to :recipe, inverse_of: :recipe_ingredients, touch: true
|
belongs_to :recipe, inverse_of: :recipe_ingredients, touch: true
|
||||||
|
|
||||||
validates :sort_order, presence: true
|
validates :sort_order, presence: true
|
||||||
|
|
||||||
def name
|
def name
|
||||||
if self.ingredient_detail.present?
|
if self.ingredient.present?
|
||||||
self.ingredient_detail.name
|
self.ingredient.name
|
||||||
else
|
else
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
@ -20,40 +20,42 @@ class RecipeIngredient < ApplicationRecord
|
|||||||
str
|
str
|
||||||
end
|
end
|
||||||
|
|
||||||
def ingredient_detail_id
|
def ingredient_id
|
||||||
case
|
case
|
||||||
when recipe_as_ingredient_id
|
when recipe_as_ingredient_id
|
||||||
"R#{recipe_as_ingredient_id}"
|
"R#{recipe_as_ingredient_id}"
|
||||||
when ingredient_id
|
when food_id
|
||||||
"I#{ingredient_id}"
|
"F#{food_id}"
|
||||||
else
|
else
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def ingredient_detail_id=(val)
|
def ingredient_id=(val)
|
||||||
@recipe_detail = nil
|
return val if self.ingredient_id == val
|
||||||
|
|
||||||
|
@ingredient = nil
|
||||||
case val
|
case val
|
||||||
when -> (v) { v.blank? }
|
when -> (v) { v.blank? }
|
||||||
self.recipe_as_ingredient_id = nil
|
self.recipe_as_ingredient_id = nil
|
||||||
self.ingredient_id = nil
|
self.food_id = nil
|
||||||
when /^R(\d+)$/
|
when /^R(\d+)$/
|
||||||
self.ingredient_id = nil
|
self.food_id = nil
|
||||||
self.recipe_as_ingredient_id = $1.to_i
|
self.recipe_as_ingredient_id = $1.to_i
|
||||||
when /^I(\d+)$/
|
when /^F(\d+)$/
|
||||||
self.recipe_as_ingredient_id = nil
|
self.recipe_as_ingredient_id = nil
|
||||||
self.ingredient_id = $1.to_i
|
self.food_id = $1.to_i
|
||||||
else
|
else
|
||||||
raise "Invalid ingredient_detail_id: #{val}"
|
raise "Invalid ingredient_id: #{val}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def ingredient_detail
|
def ingredient
|
||||||
@recipe_detail ||= case
|
@ingredient ||= case
|
||||||
when self.recipe_as_ingredient_id
|
when self.recipe_as_ingredient_id
|
||||||
RecipeProxy.new(self.recipe_as_ingredient)
|
self.recipe_as_ingredient
|
||||||
when self.ingredient_id
|
when self.food_id
|
||||||
IngredientProxy.new(self.ingredient)
|
self.food
|
||||||
else
|
else
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
@ -94,7 +96,7 @@ class RecipeIngredient < ApplicationRecord
|
|||||||
|
|
||||||
def to_volume
|
def to_volume
|
||||||
return unless self.quantity.present?
|
return unless self.quantity.present?
|
||||||
if ingredient_detail && ingredient_detail.density?
|
if ingredient && ingredient.density?
|
||||||
density = UnitConversion.parse(ingredient.density)
|
density = UnitConversion.parse(ingredient.density)
|
||||||
if density.density?
|
if density.density?
|
||||||
value_unit = UnitConversion.parse(self.quantity, self.units)
|
value_unit = UnitConversion.parse(self.quantity, self.units)
|
||||||
@ -107,44 +109,56 @@ class RecipeIngredient < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
def to_mass
|
def to_mass
|
||||||
if ingredient_detail
|
return unless self.quantity.present?
|
||||||
value_unit = as_value_unit
|
if ingredient && ingredient.density?
|
||||||
density = self.ingredient_detail.density? ? UnitConversion.parse(ingredient_detail.density) : nil
|
density = UnitConversion.parse(ingredient.density)
|
||||||
|
if density.density?
|
||||||
case
|
value_unit = UnitConversion.parse(self.quantity, self.units)
|
||||||
when value_unit.nil?
|
|
||||||
when value_unit.mass?
|
|
||||||
self.quantity = value_unit.pretty_value
|
|
||||||
self.units = value_unit.unit.to_s
|
|
||||||
when value_unit.volume? && density && density.density?
|
|
||||||
value_unit = value_unit.to_mass(density)
|
value_unit = value_unit.to_mass(density)
|
||||||
|
|
||||||
self.quantity = value_unit.pretty_value
|
self.quantity = value_unit.pretty_value
|
||||||
self.units = value_unit.unit.to_s
|
self.units = value_unit.unit.to_s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def custom_unit?
|
def get_custom_unit_equivalent
|
||||||
self.ingredient_detail && self.ingredient_detail.get_custom_unit_equivalent(self.units).present?
|
if self.ingredient
|
||||||
|
unit = self.units.present? ? self.units.downcase : ''
|
||||||
|
pair = self.ingredient.custom_units.detect do |u, e|
|
||||||
|
if unit.empty?
|
||||||
|
['each', 'ech', 'item', 'per'].include?(u.downcase)
|
||||||
|
else
|
||||||
|
[u.downcase, u.downcase.singularize, u.downcase.pluralize].any? { |uv| [unit, unit.singularize, unit.pluralize].include?(uv) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
pair ? pair[1] : nil
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_convert_to_grams?
|
def can_convert_to_grams?
|
||||||
vu = as_value_unit
|
vu = as_value_unit
|
||||||
vu.present? && (vu.mass? || (vu.volume? && self.ingredient_detail && self.ingredient_detail.density.present?))
|
vu.present? && (vu.mass? || (vu.volume? && self.ingredient && self.ingredient.density?))
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_grams
|
def to_grams
|
||||||
value_unit = as_value_unit
|
value_unit = as_value_unit
|
||||||
gram_unit = value_unit.convert('g', self.ingredient_detail ? self.ingredient_detail.density : nil)
|
gram_unit = value_unit.convert('g', self.ingredient ? self.ingredient.density : nil)
|
||||||
gram_unit.raw_value
|
gram_unit.raw_value
|
||||||
end
|
end
|
||||||
|
|
||||||
def as_value_unit
|
def as_value_unit
|
||||||
|
|
||||||
|
custom_unit = self.get_custom_unit_equivalent
|
||||||
|
|
||||||
case
|
case
|
||||||
when self.quantity.blank?
|
when self.quantity.blank?
|
||||||
nil
|
nil
|
||||||
when self.custom_unit?
|
when custom_unit.present?
|
||||||
self.ingredient_detail.get_custom_unit_equivalent(self.units).scale(self.quantity)
|
vu = UnitConversion.parse(custom_unit)
|
||||||
|
vu.scale(self.quantity)
|
||||||
when self.units.present?
|
when self.units.present?
|
||||||
UnitConversion.parse(self.quantity, self.units)
|
UnitConversion.parse(self.quantity, self.units)
|
||||||
else
|
else
|
||||||
@ -154,7 +168,7 @@ class RecipeIngredient < ApplicationRecord
|
|||||||
|
|
||||||
def log_copy
|
def log_copy
|
||||||
copy = RecipeIngredient.new
|
copy = RecipeIngredient.new
|
||||||
copy.ingredient = self.ingredient
|
copy.food = self.food
|
||||||
copy.recipe_as_ingredient = self.recipe_as_ingredient
|
copy.recipe_as_ingredient = self.recipe_as_ingredient
|
||||||
copy.name = self.name
|
copy.name = self.name
|
||||||
copy.sort_order = self.sort_order
|
copy.sort_order = self.sort_order
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
class User < ApplicationRecord
|
class User < ApplicationRecord
|
||||||
|
|
||||||
has_many :recipes, dependent: :nullify
|
has_many :recipes, dependent: :nullify
|
||||||
has_many :ingredients, dependent: :nullify
|
has_many :foods, dependent: :nullify
|
||||||
has_many :task_lists, dependent: :destroy
|
has_many :task_lists, dependent: :destroy
|
||||||
|
|
||||||
has_secure_password
|
has_secure_password
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
json.array! @ingredients do |i|
|
json.array! @foods do |i|
|
||||||
|
|
||||||
json.extract! i, :id, :name, :density
|
json.extract! i, :id, :name, :density
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
|
|
||||||
json.cache_root! [Ingredient.all, @ingredients] do
|
json.cache_root! [Food.all, @foods] do
|
||||||
|
|
||||||
json.extract! @ingredients, :total_count, :total_pages, :current_page
|
json.extract! @foods, :total_count, :total_pages, :current_page
|
||||||
json.page_size @ingredients.limit_value
|
json.page_size @foods.limit_value
|
||||||
|
|
||||||
json.ingredients @ingredients do |i|
|
json.foods @foods do |i|
|
||||||
json.extract! i, :id, :name, :ndbn, :kcal
|
json.extract! i, :id, :name, :ndbn, :kcal
|
||||||
json.usda i.ndbn.present?
|
json.usda i.ndbn.present?
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
json.array! @ingredients do |i|
|
json.array! @foods do |i|
|
||||||
|
|
||||||
json.extract! i, :id, :name, :density, :notes
|
json.extract! i, :id, :name, :density, :notes
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
json.extract! @ingredient,
|
json.extract! @food,
|
||||||
:id,
|
:id,
|
||||||
:name,
|
:name,
|
||||||
:ndbn,
|
:ndbn,
|
||||||
@ -32,15 +32,15 @@ json.extract! @ingredient,
|
|||||||
:cholesterol,
|
:cholesterol,
|
||||||
:lipids
|
:lipids
|
||||||
|
|
||||||
if @ingredient.ndbn.present?
|
if @food.ndbn.present?
|
||||||
json.ndbn_units @ingredient.usda_food.usda_food_weights do |fw|
|
json.ndbn_units @food.usda_food.usda_food_weights do |fw|
|
||||||
json.extract! fw, :amount, :description, :gram_weight
|
json.extract! fw, :amount, :description, :gram_weight
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
json.ndbn_units []
|
json.ndbn_units []
|
||||||
end
|
end
|
||||||
|
|
||||||
json.ingredient_units @ingredient.ingredient_units do |iu|
|
json.ingredient_units @food.ingredient_units do |iu|
|
||||||
json.extract! iu, :id, :name, :gram_weight
|
json.extract! iu, :id, :name, :gram_weight
|
||||||
json._destroy false
|
json._destroy false
|
||||||
end
|
end
|
@ -10,10 +10,10 @@ json.ingredients recipe.recipe_ingredients do |ri|
|
|||||||
json.extract! ri, :id, :ingredient_detail_id, :display_name, :name, :quantity, :units, :preparation, :sort_order
|
json.extract! ri, :id, :ingredient_detail_id, :display_name, :name, :quantity, :units, :preparation, :sort_order
|
||||||
|
|
||||||
json.ingredient_detail do
|
json.ingredient_detail do
|
||||||
if ri.ingredient.nil? && ri.ingredient_as_recipe.nil?
|
if ri.food.nil? && ri.ingredient_as_recipe.nil?
|
||||||
json.null!
|
json.null!
|
||||||
elsif ri.ingredient
|
elsif ri.food
|
||||||
json.extract! ri.ingredient, :name, :density, :notes
|
json.extract! ri.food, :name, :density, :notes
|
||||||
else
|
else
|
||||||
json.extract! ri.recipe_as_ingredient, :name
|
json.extract! ri.recipe_as_ingredient, :name
|
||||||
end
|
end
|
||||||
|
@ -10,7 +10,7 @@ Rails.application.routes.draw do
|
|||||||
|
|
||||||
resources :logs, except: [:new, :create]
|
resources :logs, except: [:new, :create]
|
||||||
|
|
||||||
resources :ingredients, except: [] do
|
resources :foods, except: [] do
|
||||||
collection do
|
collection do
|
||||||
get :usda_food_search
|
get :usda_food_search
|
||||||
|
|
||||||
|
9
db/migrate/20180910235229_rename_ingredient.rb
Normal file
9
db/migrate/20180910235229_rename_ingredient.rb
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
class RenameIngredient < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
rename_table :ingredients, :foods
|
||||||
|
rename_table :ingredient_units, :food_units
|
||||||
|
|
||||||
|
rename_column :food_units, :ingredient_id, :food_id
|
||||||
|
rename_column :recipe_ingredients, :ingredient_id, :food_id
|
||||||
|
end
|
||||||
|
end
|
12
db/schema.rb
12
db/schema.rb
@ -10,16 +10,16 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2018_09_06_191333) do
|
ActiveRecord::Schema.define(version: 2018_09_10_235229) do
|
||||||
|
|
||||||
create_table "ingredient_units", force: :cascade do |t|
|
create_table "food_units", force: :cascade do |t|
|
||||||
t.integer "ingredient_id", null: false
|
t.integer "food_id", null: false
|
||||||
t.string "name", null: false
|
t.string "name", null: false
|
||||||
t.decimal "gram_weight", precision: 10, scale: 2, null: false
|
t.decimal "gram_weight", precision: 10, scale: 2, null: false
|
||||||
t.index ["ingredient_id"], name: "index_ingredient_units_on_ingredient_id"
|
t.index ["food_id"], name: "index_food_units_on_food_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "ingredients", force: :cascade do |t|
|
create_table "foods", force: :cascade do |t|
|
||||||
t.string "name"
|
t.string "name"
|
||||||
t.string "density"
|
t.string "density"
|
||||||
t.text "notes"
|
t.text "notes"
|
||||||
@ -74,7 +74,7 @@ ActiveRecord::Schema.define(version: 2018_09_06_191333) do
|
|||||||
end
|
end
|
||||||
|
|
||||||
create_table "recipe_ingredients", force: :cascade do |t|
|
create_table "recipe_ingredients", force: :cascade do |t|
|
||||||
t.integer "ingredient_id"
|
t.integer "food_id"
|
||||||
t.integer "recipe_id"
|
t.integer "recipe_id"
|
||||||
t.string "name"
|
t.string "name"
|
||||||
t.integer "sort_order"
|
t.integer "sort_order"
|
||||||
|
24
db/seeds.rb
24
db/seeds.rb
@ -44,7 +44,7 @@ ingredients = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ingredients.each do |k, v|
|
ingredients.each do |k, v|
|
||||||
ingredients[k] = Ingredient.create!({user_id: dan.id}.merge(v))
|
ingredients[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', ingredient: ingredients[:flank]},
|
{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/4', units: 'cup', preparation: 'divided', ingredient: ingredients[:soy_sauce]},
|
{quantity: '1/4', units: 'cup', preparation: 'divided', food: ingredients[:soy_sauce]},
|
||||||
{quantity: '1/4', units: 'cup', preparation: 'divided', ingredient: ingredients[:shaoxing]},
|
{quantity: '1/4', units: 'cup', preparation: 'divided', food: ingredients[:shaoxing]},
|
||||||
{quantity: '2', units: 'teaspoons', preparation: '', ingredient: ingredients[:cornstarch]},
|
{quantity: '2', units: 'teaspoons', preparation: '', food: ingredients[:cornstarch]},
|
||||||
{quantity: '1/3', units: 'cup', preparation: '', ingredient: ingredients[:stock]},
|
{quantity: '1/3', units: 'cup', preparation: '', food: ingredients[:stock]},
|
||||||
{quantity: '1/4', units: 'cup', preparation: '', ingredient: ingredients[:oyster_sauce]},
|
{quantity: '1/4', units: 'cup', preparation: '', food: ingredients[:oyster_sauce]},
|
||||||
{quantity: '1', units: 'tablespoon', preparation: '', ingredient: ingredients[:sugar]},
|
{quantity: '1', units: 'tablespoon', preparation: '', food: ingredients[:sugar]},
|
||||||
{quantity: '1', units: 'teaspoon', preparation: '', ingredient: ingredients[:seasame_oil]},
|
{quantity: '1', units: 'teaspoon', preparation: '', food: ingredients[:seasame_oil]},
|
||||||
{quantity: '2', units: 'medium cloves', preparation: 'finely minced', ingredient: ingredients[:garlic]},
|
{quantity: '2', units: 'medium cloves', preparation: 'finely minced', food: ingredients[: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: '', ingredient: ingredients[:peanut_oil]},
|
{quantity: '4', units: 'tablespoons', preparation: '', food: ingredients[:peanut_oil]},
|
||||||
{quantity: '1', units: 'pound', preparation: '', ingredient: ingredients[:broccoli]},
|
{quantity: '1', units: 'pound', preparation: '', food: ingredients[: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
|
||||||
|
@ -207,7 +207,7 @@ class UsdaImporter
|
|||||||
sorted_files.each { |k, v| `rm #{v}` }
|
sorted_files.each { |k, v| `rm #{v}` }
|
||||||
end
|
end
|
||||||
|
|
||||||
Ingredient.where('ndbn != ?', '').where('ndbn IS NOT NULL').each do |i|
|
Food.where('ndbn != ?', '').where('ndbn IS NOT NULL').each do |i|
|
||||||
i.set_usda_food(i.usda_food)
|
i.set_usda_food(i.usda_food)
|
||||||
i.save!
|
i.save!
|
||||||
end
|
end
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
FactoryBot.define do
|
FactoryBot.define do
|
||||||
factory :ingredient_unit do
|
factory :food_unit do
|
||||||
ingredient
|
food
|
||||||
name 'Each'
|
name 'Each'
|
||||||
gram_weight 10.5
|
gram_weight 10.5
|
||||||
end
|
end
|
@ -1,12 +1,12 @@
|
|||||||
FactoryBot.define do
|
FactoryBot.define do
|
||||||
factory :ingredient do
|
factory :food do
|
||||||
name 'Ingredient'
|
name 'Food'
|
||||||
density nil
|
density nil
|
||||||
notes 'note note note'
|
notes 'note note note'
|
||||||
user
|
user
|
||||||
end
|
end
|
||||||
|
|
||||||
factory :ingredient_with_density, parent: :ingredient do
|
factory :food_with_density, parent: :food do
|
||||||
name 'Butter'
|
name 'Butter'
|
||||||
density '8 oz/cup'
|
density '8 oz/cup'
|
||||||
end
|
end
|
@ -2,7 +2,7 @@ FactoryBot.define do
|
|||||||
factory :recipe_ingredient do
|
factory :recipe_ingredient do
|
||||||
sort_order 1
|
sort_order 1
|
||||||
recipe
|
recipe
|
||||||
ingredient
|
food
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe Ingredient, type: :model do
|
RSpec.describe Food, type: :model do
|
||||||
|
|
||||||
describe 'validation' do
|
describe 'validation' do
|
||||||
|
|
||||||
it 'validates density' do
|
it 'validates density' do
|
||||||
i = build(:ingredient)
|
i = build(:food)
|
||||||
expect(i).to be_valid
|
expect(i).to be_valid
|
||||||
|
|
||||||
i.density = '5'
|
i.density = '5'
|
||||||
@ -25,7 +25,7 @@ RSpec.describe Ingredient, type: :model do
|
|||||||
|
|
||||||
describe 'set_usda_food' do
|
describe 'set_usda_food' do
|
||||||
it 'sets the density' do
|
it 'sets the density' do
|
||||||
i = build(:ingredient)
|
i = build(:food)
|
||||||
f = create(:salted_butter)
|
f = create(:salted_butter)
|
||||||
create(:usda_food_weight, usda_food: f)
|
create(:usda_food_weight, usda_food: f)
|
||||||
|
|
||||||
@ -35,15 +35,15 @@ RSpec.describe Ingredient, type: :model do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#custom_unit_weight' do
|
describe '#custom_units' do
|
||||||
it 'returns a ValueUnit for valid custom weights' do
|
it 'returns a hash based on food_units' do
|
||||||
i = build(:ingredient)
|
i = build(:food)
|
||||||
i.ingredient_units << IngredientUnit.new(name: 'clove', gram_weight: 20.0)
|
i.food_units << FoodUnit.new(name: 'clove', gram_weight: 20.0)
|
||||||
|
|
||||||
vu = i.custom_unit_weight('clove')
|
units = i.custom_units
|
||||||
expect(vu).not_to be_nil
|
expect(units['clove']).to be_a UnitConversion::ValueUnit
|
||||||
expect(vu.raw_value).to eq 20.0
|
expect(units['clove'].value.value).to eq 20.0
|
||||||
expect(vu.unit.to_s).to eq 'gram'
|
expect(units['clove'].unit.unit).to eq 'g'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe IngredientUnit, type: :model do
|
RSpec.describe FoodUnit, type: :model do
|
||||||
|
|
||||||
describe 'matches?' do
|
describe 'matches?' do
|
||||||
it 'matches empty units to each-like terms' do
|
it 'matches empty units to each-like terms' do
|
||||||
@ -15,16 +15,16 @@ RSpec.describe IngredientUnit, type: :model do
|
|||||||
]
|
]
|
||||||
|
|
||||||
each_terms.each do |t|
|
each_terms.each do |t|
|
||||||
expect(create(:ingredient_unit, name: t).matches?('')).to eq(true), "expected #{t} to match"
|
expect(create(:food_unit, name: t).matches?('')).to eq(true), "expected #{t} to match"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'matches unit names' do
|
it 'matches unit names' do
|
||||||
expect(create(:ingredient_unit, name: 'Clove').matches?('clove')).to eq true
|
expect(create(:food_unit, name: 'Clove').matches?('clove')).to eq true
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'matches pluralized unit names' do
|
it 'matches pluralized unit names' do
|
||||||
expect(create(:ingredient_unit, name: 'Clove').matches?('cloves')).to eq true
|
expect(create(:food_unit, name: 'Clove').matches?('cloves')).to eq true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
56
spec/models/nutrition_data_spec.rb
Normal file
56
spec/models/nutrition_data_spec.rb
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe NutritionData, type: :model do
|
||||||
|
|
||||||
|
let(:rec1_ingredients) do
|
||||||
|
[
|
||||||
|
RecipeIngredient.new({
|
||||||
|
quantity: '100',
|
||||||
|
units: 'g',
|
||||||
|
sort_order: 1,
|
||||||
|
food: create(:food, kcal: 10, protein: 2)
|
||||||
|
}),
|
||||||
|
RecipeIngredient.new({
|
||||||
|
quantity: '100',
|
||||||
|
units: 'g',
|
||||||
|
sort_order: 2,
|
||||||
|
food: create(:food, kcal: 10, lipids: 2)
|
||||||
|
})
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:recipe1) do
|
||||||
|
create(:recipe, yields: '500 g').tap do |r|
|
||||||
|
r.recipe_ingredients = rec1_ingredients
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:rec2_ingredients) do
|
||||||
|
[
|
||||||
|
RecipeIngredient.new({
|
||||||
|
quantity: '100',
|
||||||
|
units: 'g',
|
||||||
|
sort_order: 1,
|
||||||
|
recipe_as_ingredient: recipe1
|
||||||
|
}),
|
||||||
|
RecipeIngredient.new({
|
||||||
|
quantity: '100',
|
||||||
|
units: 'g',
|
||||||
|
sort_order: 2,
|
||||||
|
food: create(:food, kcal: 10, lipids: 2)
|
||||||
|
})
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:recipe2) do
|
||||||
|
create(:recipe, yields: '500 g').tap do |r|
|
||||||
|
r.recipe_ingredients = rec2_ingredients
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'runs' do
|
||||||
|
n = recipe2.nutrition_data
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
@ -5,16 +5,16 @@ RSpec.describe RecipeIngredient, type: :model do
|
|||||||
describe 'to_mass' do
|
describe 'to_mass' do
|
||||||
|
|
||||||
it 'converts volume ingredients with density' do
|
it 'converts volume ingredients with density' do
|
||||||
ri = RecipeIngredient.new(quantity: 2, units: 'tbsp', ingredient: create(:ingredient_with_density))
|
ri = RecipeIngredient.new(quantity: 2, units: 'tbsp', food: create(:food_with_density))
|
||||||
expect(ri.as_value_unit.mass?).to be_falsey
|
expect(ri.as_value_unit.mass?).to be_falsey
|
||||||
ri.to_mass
|
ri.to_mass
|
||||||
expect(ri.as_value_unit.mass?).to be_truthy
|
expect(ri.as_value_unit.mass?).to be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'converts ingredients with custom units' do
|
it 'converts ingredients with custom units' do
|
||||||
i = create(:ingredient_with_density)
|
i = create(:food_with_density)
|
||||||
i.ingredient_units << IngredientUnit.new(name: 'pat', gram_weight: 25)
|
i.food_units << FoodUnit.new(name: 'pat', gram_weight: 25)
|
||||||
ri = RecipeIngredient.new(quantity: 2, units: 'pat', ingredient: i)
|
ri = RecipeIngredient.new(quantity: 2, units: 'pat', food: i)
|
||||||
ri.to_mass
|
ri.to_mass
|
||||||
vu = ri.as_value_unit
|
vu = ri.as_value_unit
|
||||||
expect(vu.raw_value).to eq 50
|
expect(vu.raw_value).to eq 50
|
||||||
@ -58,19 +58,19 @@ RSpec.describe RecipeIngredient, type: :model do
|
|||||||
|
|
||||||
describe 'with ingredient' do
|
describe 'with ingredient' do
|
||||||
it 'returns false if unit is volume and ingredient has no density' do
|
it 'returns false if unit is volume and ingredient has no density' do
|
||||||
ri = RecipeIngredient.new(quantity: '5 1/2', units: 'cups', ingredient: create(:ingredient))
|
ri = RecipeIngredient.new(quantity: '5 1/2', units: 'cups', food: create(:food))
|
||||||
expect(ri.can_convert_to_grams?).to be_falsey
|
expect(ri.can_convert_to_grams?).to be_falsey
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns true if unit is volume and ingredient has density' do
|
it 'returns true if unit is volume and ingredient has density' do
|
||||||
ri = RecipeIngredient.new(quantity: '5 1/2', units: 'cups', ingredient: create(:ingredient_with_density))
|
ri = RecipeIngredient.new(quantity: '5 1/2', units: 'cups', food: create(:food_with_density))
|
||||||
expect(ri.can_convert_to_grams?).to be_truthy
|
expect(ri.can_convert_to_grams?).to be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'with recipe_as_ingredient' do
|
describe 'with recipe_as_ingredient' do
|
||||||
it 'return true if unit is volume and recipe has density' do
|
it 'return true if unit is volume and recipe has density' do
|
||||||
ri = RecipeIngredient.new(quantity: '5 1/2', units: 'cups', recipe_as_ingredient: create(:recipe))
|
ri = RecipeIngredient.new(quantity: '5 1/2', units: 'cups', recipe_as_ingredient: create(:recipe, yields: '4 cups, 13 oz'))
|
||||||
expect(ri.can_convert_to_grams?).to be_truthy
|
expect(ri.can_convert_to_grams?).to be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user