View raw

1 class Target < ApplicationRecord 2 include NutrientVector 3 4 has_many :target_allocations, inverse_of: :target, dependent: :destroy 5 6 after_initialize :set_defaults, if: :new_record? 7 8 validate :allocations_sum_to_100 9 10 # Recompute when allocations change; keep it simple (memoized per instance) 11 def recompute_nutrients! 12 @nutrient_values = nil 13 nutrient_values 14 end 15 16 private 17 18 def nutrient_values 19 @nutrient_values ||= get_nutrient_values 20 end 21 22 def get_nutrient_values 23 sums = Hash.new(0.0) 24 allocs = target_allocations.includes(:nutrient_profile) 25 26 allocs.each do |alloc| 27 weight = alloc.percentage.to_f / 100.0 28 profile = alloc.nutrient_profile 29 NutrientVector::NUTRIENT_KEYS.each do |k| 30 sums[k] += profile.public_send(k).to_f * weight 31 end 32 end 33 34 # Ensure all keys exist, even when there are no allocations 35 NutrientVector::NUTRIENT_KEYS.each { |k| sums[k] ||= 0.0 } 36 sums.freeze 37 end 38 39 def set_defaults 40 self.name ||= "Cible #{Date.today + 1.month}" 41 if target_allocations.empty? 42 nutrient_profiles = NutrientProfile.limit(3) 43 nutrient_profiles.each do |profile| 44 target_allocations.build(nutrient_profile: profile, percentage: 0) 45 end 46 end 47 end 48 49 def allocations_sum_to_100 50 sum = target_allocations.reject(&:marked_for_destruction?).sum { |a| a.percentage.to_f } 51 errors.add(:base, "La somme des pourcentages doit être 100%") unless (sum - 100).abs < 0.01 52 end 53 end 54