diff --git a/app/models/food.rb b/app/models/food.rb index a8f19bd..696857e 100644 --- a/app/models/food.rb +++ b/app/models/food.rb @@ -16,12 +16,16 @@ class Food < ActiveRecord::Base belongs_to :ref_unit, class_name: 'Unit', required: true belongs_to :source, required: false has_many :ingredients, dependent: :restrict_with_error + has_many :nutrients, foreign_key: 'registry_id', inverse_of: :food, dependent: :destroy, + validate: true + + DOMAIN = :diet + alias_attribute :subitems, :nutrients + scope :subitems, -> { includes(nutrients: [:quantity, :unit]) } - has_many :nutrients, inverse_of: :food, dependent: :destroy, validate: true validates :nutrients, presence: true - accepts_nested_attributes_for :nutrients, allow_destroy: true, reject_if: proc { |attrs| - attrs['quantity_id'].blank? && attrs['amount'].blank? - } + accepts_nested_attributes_for :nutrients, allow_destroy: true, + reject_if: proc { |attrs| attrs['quantity_id'].blank? && attrs['amount'].blank? } # Nutrient quantity_id uniqueness check for nested attributes validate do quantities = self.nutrients.reject { |n| n.marked_for_destruction? } diff --git a/app/models/ingredient.rb b/app/models/ingredient.rb index e7e47cf..d2c5215 100644 --- a/app/models/ingredient.rb +++ b/app/models/ingredient.rb @@ -2,6 +2,11 @@ class Ingredient < ActiveRecord::Base belongs_to :composition, inverse_of: :ingredients, polymorphic: true, required: true belongs_to :food, required: true belongs_to :part_of, required: false + has_many :nutrients, through: :food, source: :nutrients + + DOMAIN = :diet + alias_attribute :subitems, :nutrients + scope :subitems, -> { includes(nutrients: [:quantity, :unit]) } validates :ready_ratio, numericality: {greater_than_or_equal_to: 0.0} validates :amount, numericality: {greater_than_or_equal_to: 0.0} diff --git a/app/models/measurement.rb b/app/models/measurement.rb index 87685fa..48e87d9 100644 --- a/app/models/measurement.rb +++ b/app/models/measurement.rb @@ -1,19 +1,22 @@ class Measurement < ActiveRecord::Base belongs_to :routine, required: true, inverse_of: :measurements, class_name: 'MeasurementRoutine' - accepts_nested_attributes_for :routine, allow_destroy: true, reject_if: proc { |attrs| - attrs['name'].blank? - } - after_destroy { self.routine.destroy if self.routine.measurements.empty? } - has_one :project, through: :routine - belongs_to :source, required: false + has_one :project, through: :routine + has_many :readouts, foreign_key: 'registry_id', inverse_of: :measurement, + dependent: :destroy, validate: true + + DOMAIN = :measurement + alias_attribute :subitems, :readouts + scope :subitems, -> { includes(readouts: [:quantity, :unit]) } + + accepts_nested_attributes_for :routine, allow_destroy: true, + reject_if: proc { |attrs| attrs['name'].blank? } + after_destroy { self.routine.destroy if self.routine.measurements.empty? } - has_many :readouts, inverse_of: :measurement, dependent: :destroy, validate: true validates :readouts, presence: true - accepts_nested_attributes_for :readouts, allow_destroy: true, reject_if: proc { |attrs| - attrs['quantity_id'].blank? && attrs['value'].blank? - } + accepts_nested_attributes_for :readouts, allow_destroy: true, + reject_if: proc { |attrs| attrs['quantity_id'].blank? && attrs['value'].blank? } # Readout quantity_id + unit_id uniqueness validation. Cannot be effectively # checked on Readout model level. validate do diff --git a/app/models/nutrient.rb b/app/models/nutrient.rb index f896bd4..c7f6e46 100644 --- a/app/models/nutrient.rb +++ b/app/models/nutrient.rb @@ -1,9 +1,10 @@ class Nutrient < QuantityValue - belongs_to :food, inverse_of: :nutrients, required: true + belongs_to :food, foreign_key: 'registry_id', inverse_of: :nutrients, required: true - validates :value, numericality: {greater_than_or_equal_to: 0.0} # Uniqueness NOT validated here, see Value for explanation #validates :quantity, uniqueness: {scope: :food_id} + validates :value, numericality: {greater_than_or_equal_to: 0.0} alias_attribute :amount, :value + delegate :ref_amount, to: :food end diff --git a/app/models/readout.rb b/app/models/readout.rb index ca72b6d..52de298 100644 --- a/app/models/readout.rb +++ b/app/models/readout.rb @@ -1,7 +1,7 @@ class Readout < QuantityValue - belongs_to :measurement, inverse_of: :readouts, required: true + belongs_to :measurement, foreign_key: 'registry_id', inverse_of: :readouts, required: true - validates :value, numericality: true # Uniqueness NOT validated here, see Value for explanation #validates :quantity, uniqueness: {scope: [:measurement_id, :unit_id]} + validates :value, numericality: true end diff --git a/lib/body_tracking/items_with_quantities.rb b/lib/body_tracking/items_with_quantities.rb index 69946c5..8d52dad 100644 --- a/lib/body_tracking/items_with_quantities.rb +++ b/lib/body_tracking/items_with_quantities.rb @@ -1,23 +1,5 @@ module BodyTracking module ItemsWithQuantities - ITEM_TYPES = { - 'Ingredient' => { - domain: :diet, - associations: [:food, :nutrients], - value_field: :amount - }, - 'Food' => { - domain: :diet, - associations: [:nutrients], - value_field: :amount - }, - 'Measurement' => { - domain: :measurement, - associations: [:readouts], - value_field: :value - } - } - def filter(filters, requested_q = nil) items = all @@ -33,11 +15,10 @@ module BodyTracking if filters[:formula][:code].present? owner = proxy_association.owner project = owner.is_a?(Project) ? owner : owner.project - domain = ITEM_TYPES[proxy_association.klass.name][:domain] filter_q_attrs = { name: 'Filter formula', formula_attributes: filters[:formula], - domain: domain + domain: proxy_association.klass::DOMAIN } project.quantities.new(filter_q_attrs) end @@ -56,23 +37,10 @@ module BodyTracking def compute_quantities(requested_q, filter_q = nil) items = all - item_type = ITEM_TYPES[proxy_association.klass.name] subitems = Hash.new { |h,k| h[k] = {} } - # Ingredient.includes(food: {nutrients: [:quantity, :unit]}).order('quantities.lft') - # Food.includes(nutrients: [:quantity, :unit]).order('quantities.lft') - includes = item_type[:associations].reverse - .inject([:quantity, :unit]) { |relation, assoc| {assoc => relation} } - all.includes(includes).order('quantities.lft').each do |i| - item_type[:associations].inject(i) { |o, m| o.send(m) }.each do |s| - subitem_value = - if i.respond_to?(item_type[:value_field]) - s_value = s.send(item_type[:value_field]) - i_value = i.send(item_type[:value_field]) - # NOTE: for now scaling is designed only for Ingredients - s_value * i_value / i.food.ref_amount - else - s.send(item_type[:value_field]) - end + all.subitems.order('quantities.lft').each do |i| + i.subitems.each do |s| + subitem_value = i.respond_to?(:amount) ? i.amount*s.amount/s.ref_amount : s.value subitems[s.quantity][i] = [subitem_value, s.unit] end end