Files
growstuff/app/models/harvest.rb
T
Brenda Wallace 54258de6c4 Refactor home dashboard and related components
- Removed unused styles and helper methods from _garden_layout.scss, _homepage.scss, and overrides.scss.
- Updated _home_dashboard.scss to enhance button styles and added new harvest picker styles.
- Introduced HarvestPicker component for improved harvest recording functionality.
- Refactored home dashboard views to utilize new home_section helper for consistent layout.
- Simplified and optimized existing methods in application_helper.rb, activity.rb, and harvest.rb.
- Removed deprecated homepage_records methods from Activity and Harvest models.
- Updated tests to reflect changes in helper methods and removed obsolete tests.
2026-10-12 19:24:55 +13:00

187 lines
5.1 KiB
Ruby

# frozen_string_literal: true
class Harvest < ApplicationRecord
include ActionView::Helpers::NumberHelper
extend FriendlyId
include PhotoCapable
include Ownable
include Likeable
attr_accessor :overall_rating
friendly_id :harvest_slug, use: %i(slugged finders)
# Constants
UNITS_VALUES = {
"individual" => "individual",
"bunches" => "bunch",
"sprigs" => "sprig",
"handfuls" => "handful",
"litres" => "litre",
"pints" => "pint",
"quarts" => "quart",
"buckets" => "bucket",
"baskets" => "basket",
"bushels" => "bushel"
}.freeze
WEIGHT_UNITS_VALUES = {
"kg" => "kg",
"lb" => "lb",
"oz" => "oz"
}.freeze
# Exact definitions of the international avoirdupois units, in kilograms.
KG_PER_WEIGHT_UNIT = {
"kg" => BigDecimal("1"),
"lb" => BigDecimal("0.45359237"),
"oz" => BigDecimal("0.028349523125")
}.freeze
##
## Triggers
after_validation :cleanup_quantities
before_save :set_si_weight
##
## Relationships
belongs_to :crop, counter_cache: true
belongs_to :plant_part, counter_cache: true
belongs_to :planting, optional: true, counter_cache: true
##
## Scopes
scope :interesting, -> { has_photos.one_per_owner }
scope :recent, -> { order(created_at: :desc) }
scope :one_per_owner, lambda {
joins("JOIN members m ON (m.id=harvests.owner_id)
LEFT OUTER JOIN harvests h2
ON (m.id=h2.owner_id AND harvests.id < h2.id)").where("h2 IS NULL")
}
delegate :name, :slug, to: :crop, prefix: true
delegate :login_name, :slug, to: :owner, prefix: true
delegate :name, to: :plant_part, prefix: true
##
## Validations
validates :crop, approved: true
validates :crop, presence: { message: :crop_not_found }
validates :plant_part, presence: { message: :crop_not_found }
validates :harvested_at, presence: true
validates :quantity, allow_nil: true, numericality: {
only_integer: false, greater_than_or_equal_to: 0
}
validates :unit, allow_blank: true, inclusion: {
in: UNITS_VALUES.values, message: :not_a_valid_unit
}
validates :weight_quantity, allow_nil: true, numericality: { only_integer: false }
validates :weight_unit, allow_blank: true, inclusion: {
in: WEIGHT_UNITS_VALUES.values, message: :not_a_valid_unit
}
validate :crop_must_match_planting
validate :owner_must_match_planting
validate :harvest_must_be_after_planting
def time_from_planting_to_harvest
return if planting.blank?
harvested_at - planting.planted_at
end
def default_photo
most_liked_photo || planting&.default_photo
end
# we're storing the harvest weight in kilograms in the db too
# to make data manipulation easier
def set_si_weight
return if weight_unit.nil?
self.si_weight = (weight_quantity * KG_PER_WEIGHT_UNIT.fetch(weight_unit)).round(3).to_f
end
def cleanup_quantities
self.quantity = nil if quantity&.zero?
self.unit = nil if quantity.blank?
self.weight_quantity = nil if weight_quantity&.zero?
self.weight_unit = nil if weight_quantity.blank?
end
def harvest_slug
"#{owner.login_name}-#{crop}".downcase.tr(' ', '-')
end
# stringify as "beet in Skud's backyard" or similar
def to_s
# 50 individual apples, weighing 3lb
# 2 buckets of apricots, weighing 10kg
@to_s ||= "#{quantity_to_human} #{unit_to_human} #{crop_name_to_human} #{weight_to_human}".strip
end
def quantity_to_human
@quantity_to_human ||= if quantity
number_to_human(quantity.to_s, strip_insignificant_zeros: true)
else
""
end
end
def unit_to_human
@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
@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
@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
def crop_must_match_planting
return if planting.blank? # only check if we are linked to a planting
errors.add(:planting, :same_crop_required) unless crop == planting.crop
end
def owner_must_match_planting
return if planting.blank? # only check if we are linked to a planting
return if owner == planting.owner || planting.garden.garden_collaborators.where(member_id: owner).any?
errors.add(:owner, :same_owner_required)
end
def harvest_must_be_after_planting
# only check if we are linked to a planting
return unless harvested_at.present? && planting.present? && planting.planted_at.present?
errors.add(:planting, :harvest_after_planted) unless harvested_at > planting.planted_at
end
end