[Rails] Fertilizer recipe solver for the FAPG.
1
classTarget<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