rai
This commit is contained in:
parent
a2f2a05679
commit
021c066cf4
25
app/models/ingredient_proxy.rb
Normal file
25
app/models/ingredient_proxy.rb
Normal file
@ -0,0 +1,25 @@
|
||||
class IngredientProxy
|
||||
|
||||
attr_reader :ingredient
|
||||
|
||||
def initialize(ingredient)
|
||||
@ingredient = ingredient
|
||||
end
|
||||
|
||||
def name
|
||||
@ingredient.name
|
||||
end
|
||||
|
||||
def density
|
||||
@ingredient.density
|
||||
end
|
||||
|
||||
def density?
|
||||
@ingredient.density.present?
|
||||
end
|
||||
|
||||
def get_custom_unit_equivalent(custom_unit_name)
|
||||
@ingredient.custom_unit_weight(custom_unit_name)
|
||||
end
|
||||
|
||||
end
|
@ -69,6 +69,14 @@ class Recipe < ApplicationRecord
|
||||
self
|
||||
end
|
||||
|
||||
def yields_list
|
||||
if self.yields.present?
|
||||
self.yields.split(',').map { |y| y.strip }.select { |y| y.present? }
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def tag_names
|
||||
self.tags.map { |t| t.name }
|
||||
end
|
||||
@ -90,13 +98,6 @@ class Recipe < ApplicationRecord
|
||||
@nutrition_data
|
||||
end
|
||||
|
||||
def parsed_yield
|
||||
if @parsed_yield.nil? && self.yields.present?
|
||||
@parsed_yield = YieldParser.parse(self.yields)
|
||||
end
|
||||
@parsed_yield
|
||||
end
|
||||
|
||||
def update_rating!
|
||||
self.rating = Log.for_recipe(self).for_user(self.user_id).where('rating IS NOT NULL').average(:rating)
|
||||
save(validate: false)
|
||||
|
@ -1,13 +1,14 @@
|
||||
class RecipeIngredient < ApplicationRecord
|
||||
|
||||
belongs_to :ingredient, optional: true
|
||||
belongs_to :recipe_as_ingredient, class_name: 'Recipe', optional: true
|
||||
belongs_to :recipe, inverse_of: :recipe_ingredients, touch: true
|
||||
|
||||
validates :sort_order, presence: true
|
||||
|
||||
def name
|
||||
if self.ingredient_id.present?
|
||||
self.ingredient.name
|
||||
if self.ingredient_detail.present?
|
||||
self.ingredient_detail.name
|
||||
else
|
||||
super
|
||||
end
|
||||
@ -19,6 +20,45 @@ class RecipeIngredient < ApplicationRecord
|
||||
str
|
||||
end
|
||||
|
||||
def ingredient_detail_id
|
||||
case
|
||||
when recipe_as_ingredient_id
|
||||
"R#{recipe_as_ingredient_id}"
|
||||
when ingredient_id
|
||||
"I#{ingredient_id}"
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def ingredient_detail_id=(val)
|
||||
@recipe_detail = nil
|
||||
case val
|
||||
when -> (v) { v.blank? }
|
||||
self.recipe_as_ingredient_id = nil
|
||||
self.ingredient_id = nil
|
||||
when /^R(\d+)$/
|
||||
self.ingredient_id = nil
|
||||
self.recipe_as_ingredient_id = $1.to_i
|
||||
when /^I(\d+)$/
|
||||
self.recipe_as_ingredient_id = nil
|
||||
self.ingredient_id = $1.to_i
|
||||
else
|
||||
raise "Invalid ingredient_detail_id: #{val}"
|
||||
end
|
||||
end
|
||||
|
||||
def ingredient_detail
|
||||
@recipe_detail ||= case
|
||||
when self.recipe_as_ingredient_id
|
||||
RecipeProxy.new(self.recipe_as_ingredient)
|
||||
when self.ingredient_id
|
||||
IngredientProxy.new(self.ingredient)
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def scale(factor, auto_unit = false)
|
||||
if factor.present? && self.quantity.present? && factor != '1'
|
||||
|
||||
@ -54,7 +94,7 @@ class RecipeIngredient < ApplicationRecord
|
||||
|
||||
def to_volume
|
||||
return unless self.quantity.present?
|
||||
if ingredient && ingredient.density
|
||||
if ingredient_detail && ingredient_detail.density?
|
||||
density = UnitConversion.parse(ingredient.density)
|
||||
if density.density?
|
||||
value_unit = UnitConversion.parse(self.quantity, self.units)
|
||||
@ -67,9 +107,9 @@ class RecipeIngredient < ApplicationRecord
|
||||
end
|
||||
|
||||
def to_mass
|
||||
if ingredient
|
||||
if ingredient_detail
|
||||
value_unit = as_value_unit
|
||||
density = self.ingredient.density? ? UnitConversion.parse(ingredient.density) : nil
|
||||
density = self.ingredient_detail.density? ? UnitConversion.parse(ingredient_detail.density) : nil
|
||||
|
||||
case
|
||||
when value_unit.nil?
|
||||
@ -85,17 +125,17 @@ class RecipeIngredient < ApplicationRecord
|
||||
end
|
||||
|
||||
def custom_unit?
|
||||
self.ingredient && self.ingredient.custom_unit_weight(self.units).present?
|
||||
self.ingredient_detail && self.ingredient_detail.get_custom_unit_equivalent(self.units).present?
|
||||
end
|
||||
|
||||
def can_convert_to_grams?
|
||||
vu = as_value_unit
|
||||
vu.present? && (vu.mass? || (vu.volume? && self.ingredient && self.ingredient.density.present?))
|
||||
vu.present? && (vu.mass? || (vu.volume? && self.ingredient_detail && self.ingredient_detail.density.present?))
|
||||
end
|
||||
|
||||
def to_grams
|
||||
value_unit = as_value_unit
|
||||
gram_unit = value_unit.convert('g', self.ingredient ? self.ingredient.density : nil)
|
||||
gram_unit = value_unit.convert('g', self.ingredient_detail ? self.ingredient_detail.density : nil)
|
||||
gram_unit.raw_value
|
||||
end
|
||||
|
||||
@ -104,7 +144,7 @@ class RecipeIngredient < ApplicationRecord
|
||||
when self.quantity.blank?
|
||||
nil
|
||||
when self.custom_unit?
|
||||
self.ingredient.custom_unit_weight(self.units).scale(self.quantity)
|
||||
self.ingredient_detail.get_custom_unit_equivalent(self.units).scale(self.quantity)
|
||||
when self.units.present?
|
||||
UnitConversion.parse(self.quantity, self.units)
|
||||
else
|
||||
@ -115,6 +155,7 @@ class RecipeIngredient < ApplicationRecord
|
||||
def log_copy
|
||||
copy = RecipeIngredient.new
|
||||
copy.ingredient = self.ingredient
|
||||
copy.recipe_as_ingredient = self.recipe_as_ingredient
|
||||
copy.name = self.name
|
||||
copy.sort_order = self.sort_order
|
||||
copy.quantity = self.quantity
|
||||
|
71
app/models/recipe_proxy.rb
Normal file
71
app/models/recipe_proxy.rb
Normal file
@ -0,0 +1,71 @@
|
||||
class RecipeProxy
|
||||
|
||||
attr_reader :recipe
|
||||
|
||||
def initialize(recipe)
|
||||
@recipe = recipe
|
||||
parse_yields
|
||||
end
|
||||
|
||||
def name
|
||||
@recipe.name
|
||||
end
|
||||
|
||||
def density
|
||||
@density
|
||||
end
|
||||
|
||||
def density?
|
||||
!self.density.nil?
|
||||
end
|
||||
|
||||
def get_custom_unit_equivalent(custom_unit_name)
|
||||
unit = @custom_yields.detect { |vu| vu.unit.unit == custom_unit_name }
|
||||
known_unit = @unit_yields.first
|
||||
if unit && known_unit
|
||||
# ex:
|
||||
# custom_unit_name: "rolls"
|
||||
# yields: "3 rolls, 500 g"
|
||||
# desired return: 166.6 g
|
||||
|
||||
ValueUnit.for(known_unit.value.value / unit.value.value, known_unit.unit)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def parse_yields
|
||||
@custom_yields = []
|
||||
@unit_yields = []
|
||||
@density = nil
|
||||
|
||||
@recipe.yields_list.each do |y|
|
||||
begin
|
||||
vu = UnitConversion::parse(yield_string)
|
||||
rescue UnparseableUnitError
|
||||
vu = nil
|
||||
end
|
||||
|
||||
if vu
|
||||
if vu.unit.nil?
|
||||
@custom_yields << ValueUnit.for(vu.value, 'servings')
|
||||
elsif vu.mass? || vu.volume?
|
||||
@unit_yields << vu
|
||||
else
|
||||
@custom_yields << vu
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
vol = @unit_yields.detect { |u| u.volume? }
|
||||
mas = @unit_yields.detect { |u| u.mass? }
|
||||
# ex
|
||||
# vol: 2 cups
|
||||
# mas: 7 oz
|
||||
if vol && mas
|
||||
@density = "#{mas.value.value / vol.value.value} #{mas.unit.original_unit}/#{vol.unit.original_unit}"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
@ -7,13 +7,15 @@ json.rendered_steps MarkdownProcessor.render(recipe.step_text)
|
||||
json.tags recipe.tag_names
|
||||
|
||||
json.ingredients recipe.recipe_ingredients do |ri|
|
||||
json.extract! ri, :id, :ingredient_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 do
|
||||
if ri.ingredient.nil?
|
||||
json.ingredient_detail do
|
||||
if ri.ingredient.nil? && ri.ingredient_as_recipe.nil?
|
||||
json.null!
|
||||
elsif ri.ingredient
|
||||
json.extract! ri.ingredient, :name, :density, :notes
|
||||
else
|
||||
json.extract! ri.ingredient, :id, :name, :density, :notes
|
||||
json.extract! ri.recipe_as_ingredient, :name
|
||||
end
|
||||
end
|
||||
|
||||
|
5
db/migrate/20180823174505_add_recipe_as_ingredient_id.rb
Normal file
5
db/migrate/20180823174505_add_recipe_as_ingredient_id.rb
Normal file
@ -0,0 +1,5 @@
|
||||
class AddRecipeAsIngredientId < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
add_column :recipe_ingredients, :recipe_as_ingredient_id, :integer
|
||||
end
|
||||
end
|
@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2017_04_14_233856) do
|
||||
ActiveRecord::Schema.define(version: 2018_08_23_174505) do
|
||||
|
||||
create_table "ingredient_units", force: :cascade do |t|
|
||||
t.integer "ingredient_id", null: false
|
||||
@ -83,6 +83,7 @@ ActiveRecord::Schema.define(version: 2017_04_14_233856) do
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.text "preparation"
|
||||
t.integer "recipe_as_ingredient_id"
|
||||
t.index ["recipe_id"], name: "index_recipe_ingredients_on_recipe_id"
|
||||
end
|
||||
|
||||
|
@ -24,45 +24,58 @@ RSpec.describe RecipeIngredient, type: :model do
|
||||
end
|
||||
|
||||
describe '#can_convert_to_grams' do
|
||||
it 'returns false if no quantity or unit' do
|
||||
ri = RecipeIngredient.new
|
||||
expect(ri.can_convert_to_grams?).to be_falsey
|
||||
describe 'with no ingredient detail' do
|
||||
it 'returns false if no quantity or unit' do
|
||||
ri = RecipeIngredient.new
|
||||
expect(ri.can_convert_to_grams?).to be_falsey
|
||||
end
|
||||
|
||||
it 'returns false if no quantity' do
|
||||
ri = RecipeIngredient.new(units: 'lbs')
|
||||
expect(ri.can_convert_to_grams?).to be_falsey
|
||||
end
|
||||
|
||||
it 'returns false if no units' do
|
||||
ri = RecipeIngredient.new(quantity: '5 1/2')
|
||||
expect(ri.can_convert_to_grams?).to be_falsey
|
||||
end
|
||||
|
||||
it 'returns false if weird units' do
|
||||
ri = RecipeIngredient.new(quantity: '5 1/2', units: 'dogs')
|
||||
expect(ri.can_convert_to_grams?).to be_falsey
|
||||
end
|
||||
|
||||
it 'returns true if unit is mass' do
|
||||
ri = RecipeIngredient.new(quantity: '5 1/2', units: 'lbs')
|
||||
expect(ri.can_convert_to_grams?).to be_truthy
|
||||
end
|
||||
|
||||
it 'returns false if unit is volume' do
|
||||
ri = RecipeIngredient.new(quantity: '5 1/2', units: 'cups')
|
||||
expect(ri.can_convert_to_grams?).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns false if no quantity' do
|
||||
ri = RecipeIngredient.new(units: 'lbs')
|
||||
expect(ri.can_convert_to_grams?).to be_falsey
|
||||
describe 'with ingredient' 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))
|
||||
expect(ri.can_convert_to_grams?).to be_falsey
|
||||
end
|
||||
|
||||
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))
|
||||
expect(ri.can_convert_to_grams?).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns false if no units' do
|
||||
ri = RecipeIngredient.new(quantity: '5 1/2')
|
||||
expect(ri.can_convert_to_grams?).to be_falsey
|
||||
describe 'with recipe_as_ingredient' 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))
|
||||
expect(ri.can_convert_to_grams?).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns false if weird units' do
|
||||
ri = RecipeIngredient.new(quantity: '5 1/2', units: 'dogs')
|
||||
expect(ri.can_convert_to_grams?).to be_falsey
|
||||
end
|
||||
|
||||
it 'returns true if unit is mass' do
|
||||
ri = RecipeIngredient.new(quantity: '5 1/2', units: 'lbs')
|
||||
expect(ri.can_convert_to_grams?).to be_truthy
|
||||
end
|
||||
|
||||
it 'returns false if unit is volume and there is no ingredient' do
|
||||
ri = RecipeIngredient.new(quantity: '5 1/2', units: 'cups')
|
||||
expect(ri.can_convert_to_grams?).to be_falsey
|
||||
end
|
||||
|
||||
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))
|
||||
expect(ri.can_convert_to_grams?).to be_falsey
|
||||
end
|
||||
|
||||
it 'returns false if unit is volume and ingredient has density' do
|
||||
ri = RecipeIngredient.new(quantity: '5 1/2', units: 'cups', ingredient: create(:ingredient_with_density))
|
||||
expect(ri.can_convert_to_grams?).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user