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_detail.present? self.ingredient_detail.name else super end end def display_name str = [quantity, units, name].delete_if { |i| i.blank? }.join(' ') str << ", #{preparation}" if preparation.present? 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' value_unit = UnitConversion.parse(self.quantity, self.units) value_unit = value_unit.scale(factor) if auto_unit value_unit = value_unit.auto_unit end self.quantity = value_unit.pretty_value self.units = value_unit.unit.to_s end end def to_metric return unless self.quantity.present? value_unit = UnitConversion.parse(self.quantity, self.units) value_unit = value_unit.to_metric self.quantity = value_unit.pretty_value self.units = value_unit.unit.to_s end def to_standard return unless self.quantity.present? value_unit = UnitConversion.parse(self.quantity, self.units) value_unit = value_unit.to_standard self.quantity = value_unit.pretty_value self.units = value_unit.unit.to_s end def to_volume return unless self.quantity.present? if ingredient_detail && ingredient_detail.density? density = UnitConversion.parse(ingredient.density) if density.density? value_unit = UnitConversion.parse(self.quantity, self.units) value_unit = value_unit.to_volume(density) self.quantity = value_unit.pretty_value self.units = value_unit.unit.to_s end end end def to_mass if ingredient_detail value_unit = as_value_unit density = self.ingredient_detail.density? ? UnitConversion.parse(ingredient_detail.density) : nil case 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) self.quantity = value_unit.pretty_value self.units = value_unit.unit.to_s end end end def custom_unit? 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_detail && self.ingredient_detail.density.present?)) end def to_grams value_unit = as_value_unit gram_unit = value_unit.convert('g', self.ingredient_detail ? self.ingredient_detail.density : nil) gram_unit.raw_value end def as_value_unit case when self.quantity.blank? nil when self.custom_unit? self.ingredient_detail.get_custom_unit_equivalent(self.units).scale(self.quantity) when self.units.present? UnitConversion.parse(self.quantity, self.units) else nil end end 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 copy.units = self.units copy.preparation = self.preparation copy end end