From fa77a691ce0cc8941fe470a762f352b27f4f0563 Mon Sep 17 00:00:00 2001 From: Marius Peter Date: Sun, 23 Nov 2025 17:54:45 +0100 Subject: Last commit. --- app/models/target.rb | 67 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 28 deletions(-) (limited to 'app/models/target.rb') diff --git a/app/models/target.rb b/app/models/target.rb index 9211e74..2efd3b2 100644 --- a/app/models/target.rb +++ b/app/models/target.rb @@ -1,42 +1,53 @@ -# app/models/target.rb class Target < ApplicationRecord - has_many :target_allocations, dependent: :destroy - has_many :nutrient_profiles, through: :target_allocations + include NutrientVector - accepts_nested_attributes_for :target_allocations, allow_destroy: true - # validate :percentages_sum_to_100 + has_many :target_allocations, inverse_of: :target, dependent: :destroy - def weighted_requirements - totals = Hash.new(0.0) - denom = 100.0 + after_initialize :set_defaults, if: :new_record? - target_allocations.includes(:nutrient_profile).each do |alloc| - profile = alloc.nutrient_profile - next unless profile + validate :allocations_sum_to_100 - weight = (alloc.percentage || 0).to_f / denom - next if weight <= 0 + # Recompute when allocations change; keep it simple (memoized per instance) + def recompute_nutrients! + @nutrient_values = nil + nutrient_values + end - # Prefer the helper, but gracefully fall back to slicing attributes. - reqs = if profile.respond_to?(:requirements_hash) - profile.requirements_hash - else - profile.attributes.slice(*NutrientProfile::NUTRIENT_KEYS.map(&:to_s)) - end + private + + def nutrient_values + @nutrient_values ||= get_nutrient_values + end + + def get_nutrient_values + sums = Hash.new(0.0) + allocs = target_allocations.includes(:nutrient_profile) - reqs.each do |nutrient_key, value| - next if value.nil? - totals[nutrient_key.to_s] += value.to_f * weight + allocs.each do |alloc| + weight = alloc.percentage.to_f / 100.0 + profile = alloc.nutrient_profile + NutrientVector::NUTRIENT_KEYS.each do |k| + sums[k] += profile.public_send(k).to_f * weight end end - totals + # Ensure all keys exist, even when there are no allocations + NutrientVector::NUTRIENT_KEYS.each { |k| sums[k] ||= 0.0 } + sums.freeze end - private + def set_defaults + self.name ||= "Cible #{Date.today + 1.month}" + if target_allocations.empty? + nutrient_profiles = NutrientProfile.limit(3) + nutrient_profiles.each do |profile| + target_allocations.build(nutrient_profile: profile, percentage: 0) + end + end + end - # def percentages_sum_to_100 - # sum = target_allocations.sum { |a| a.percentage.to_f } - # errors.add(:base, "La somme des pourcentages doit être égale à 100%") unless (sum - 100.0).abs <= 0.1 - # end + def allocations_sum_to_100 + sum = target_allocations.reject(&:marked_for_destruction?).sum { |a| a.percentage.to_f } + errors.add(:base, "La somme des pourcentages doit être 100%") unless (sum - 100).abs < 0.01 + end end -- cgit v1.2.3