From 0df7589feb6a42c500e5490018ed5ff3b61b7062 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 02:59:06 +0000 Subject: [PATCH 1/3] Optimize Harvests with memoization and fragment caching - Memoize display methods in `Harvest` model. - Memoize calculation methods in `PredictHarvest` concern using `defined?` for nil safety. - Add fragment caching to `app/views/harvests/_popover.html.haml`. - Add fragment caching to `app/views/crops/_harvests.html.haml` with daily expiration for relative time strings. Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> --- app/models/concerns/predict_harvest.rb | 20 +++++++---- app/models/harvest.rb | 50 ++++++++++++++++---------- app/views/crops/_harvests.html.haml | 15 ++++---- app/views/harvests/_popover.html.haml | 7 ++-- 4 files changed, 57 insertions(+), 35 deletions(-) diff --git a/app/models/concerns/predict_harvest.rb b/app/models/concerns/predict_harvest.rb index 64d7063d2..4a839fdef 100644 --- a/app/models/concerns/predict_harvest.rb +++ b/app/models/concerns/predict_harvest.rb @@ -6,23 +6,31 @@ module PredictHarvest included do # dates def first_harvest_date - harvests_with_dates.minimum(:harvested_at) + return @first_harvest_date if defined?(@first_harvest_date) + + @first_harvest_date = harvests_with_dates.minimum(:harvested_at) end def last_harvest_date - harvests_with_dates.maximum(:harvested_at) + return @last_harvest_date if defined?(@last_harvest_date) + + @last_harvest_date = harvests_with_dates.maximum(:harvested_at) end def first_harvest_predicted_at - return unless crop.median_days_to_first_harvest.present? && planted_at.present? + return @first_harvest_predicted_at if defined?(@first_harvest_predicted_at) - planted_at + crop.median_days_to_first_harvest.days + @first_harvest_predicted_at = if crop.median_days_to_first_harvest.present? && planted_at.present? + planted_at + crop.median_days_to_first_harvest.days + end end def last_harvest_predicted_at - return unless crop.median_days_to_last_harvest.present? && planted_at.present? + return @last_harvest_predicted_at if defined?(@last_harvest_predicted_at) - planted_at + crop.median_days_to_last_harvest.days + @last_harvest_predicted_at = if crop.median_days_to_last_harvest.present? && planted_at.present? + planted_at + crop.median_days_to_last_harvest.days + end end # actions diff --git a/app/models/harvest.rb b/app/models/harvest.rb index 92ed0f6eb..5b2b05cfe 100644 --- a/app/models/harvest.rb +++ b/app/models/harvest.rb @@ -109,37 +109,49 @@ class Harvest < ApplicationRecord def to_s # 50 individual apples, weighing 3lb # 2 buckets of apricots, weighing 10kg - "#{quantity_to_human} #{unit_to_human} #{crop_name_to_human} #{weight_to_human}".strip + @to_s ||= "#{quantity_to_human} #{unit_to_human} #{crop_name_to_human} #{weight_to_human}".strip end def quantity_to_human - return number_to_human(quantity.to_s, strip_insignificant_zeros: true) if quantity - - "" + @quantity_to_human ||= if quantity + number_to_human(quantity.to_s, strip_insignificant_zeros: true) + else + "" + end end def unit_to_human - return "" unless quantity && unit - return 'individual' if unit == 'individual' - return "#{unit} of" if quantity == 1 - - "#{unit.pluralize} of" + @unit_to_human ||= begin + if !quantity || !unit + "" + elsif unit == 'individual' + 'individual' + elsif quantity == 1 + "#{unit} of" + else + "#{unit.pluralize} of" + end + end end def weight_to_human - return "" unless weight_quantity - - "weighing #{number_to_human(weight_quantity, strip_insignificant_zeros: true)} #{weight_unit}" + @weight_to_human ||= if weight_quantity + "weighing #{number_to_human(weight_quantity, strip_insignificant_zeros: true)} #{weight_unit}" + else + "" + end end def crop_name_to_human - if unit != 'individual' # buckets of apricot*s* - crop.name.pluralize - elsif quantity == 1 - crop.name - else - crop.name.pluralize - end.to_s + @crop_name_to_human ||= begin + if unit != 'individual' # buckets of apricot*s* + crop.name.pluralize + elsif quantity == 1 + crop.name + else + crop.name.pluralize + end.to_s + end end private diff --git a/app/views/crops/_harvests.html.haml b/app/views/crops/_harvests.html.haml index 47f43d57a..aaa09319b 100644 --- a/app/views/crops/_harvests.html.haml +++ b/app/views/crops/_harvests.html.haml @@ -6,13 +6,14 @@ - unless crop.harvests.empty? %ul.list-group.list-group-flush - Harvest.where(crop: crop).includes(:owner).order(harvested_at: :desc).limit(3).each do |harvest| - %li.list-group-item - = link_to harvest_path(harvest), class: 'card-link' do - = harvest_icon - #{harvest.owner} harvested #{display_quantity(harvest)}. - .float-right= render 'members/location', member: harvest.owner - .harvest-timeago - %small #{standard_time_distance(harvest.harvested_at, Time.zone.now.to_date)} + - cache [harvest, Time.zone.today] do + %li.list-group-item + = link_to harvest_path(harvest), class: 'card-link' do + = harvest_icon + #{harvest.owner} harvested #{display_quantity(harvest)}. + .float-right= render 'members/location', member: harvest.owner + .harvest-timeago + %small #{standard_time_distance(harvest.harvested_at, Time.zone.now.to_date)} %li.list-group-item= link_to "View all #{crop.name} harvests", crop_harvests_path(crop), class: 'card-link' - if crop.approved? - if current_member diff --git a/app/views/harvests/_popover.html.haml b/app/views/harvests/_popover.html.haml index 508413918..f16f141e7 100644 --- a/app/views/harvests/_popover.html.haml +++ b/app/views/harvests/_popover.html.haml @@ -1,3 +1,4 @@ -%p - %small - = harvest.harvested_at +- cache harvest do + %p + %small + = harvest.harvested_at From 50ab6f39eee4304a106cad126f6563dbebde930b Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 03:16:36 +0000 Subject: [PATCH 2/3] Optimize Harvests with memoization and caching - Memoize display methods in `Harvest` model. - Memoize calculation methods in `PredictHarvest` concern using `defined?` for nil safety. - Add fragment caching to `app/views/harvests/_popover.html.haml`. - Add fragment caching and query caching to `app/views/crops/_harvests.html.haml` with daily expiration for relative time strings. Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com> --- app/views/crops/_harvests.html.haml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/crops/_harvests.html.haml b/app/views/crops/_harvests.html.haml index aaa09319b..1d80f8b27 100644 --- a/app/views/crops/_harvests.html.haml +++ b/app/views/crops/_harvests.html.haml @@ -5,7 +5,8 @@ %p Nobody has harvested this crop yet. - unless crop.harvests.empty? %ul.list-group.list-group-flush - - Harvest.where(crop: crop).includes(:owner).order(harvested_at: :desc).limit(3).each do |harvest| + - Rails.cache.fetch([crop, "recent_harvests", Time.zone.today]) do + - Harvest.where(crop: crop).includes(:owner).order(harvested_at: :desc).limit(3).each do |harvest| - cache [harvest, Time.zone.today] do %li.list-group-item = link_to harvest_path(harvest), class: 'card-link' do From 22638371c245141e89b5bf17c0f171ea883aece2 Mon Sep 17 00:00:00 2001 From: Daniel O'Connor Date: Tue, 28 Apr 2026 13:01:02 +0930 Subject: [PATCH 3/3] Update _harvests.html.haml --- app/views/crops/_harvests.html.haml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/views/crops/_harvests.html.haml b/app/views/crops/_harvests.html.haml index 1d80f8b27..54ecf142a 100644 --- a/app/views/crops/_harvests.html.haml +++ b/app/views/crops/_harvests.html.haml @@ -7,7 +7,6 @@ %ul.list-group.list-group-flush - Rails.cache.fetch([crop, "recent_harvests", Time.zone.today]) do - Harvest.where(crop: crop).includes(:owner).order(harvested_at: :desc).limit(3).each do |harvest| - - cache [harvest, Time.zone.today] do %li.list-group-item = link_to harvest_path(harvest), class: 'card-link' do = harvest_icon