Files
growstuff/app/models/problem.rb
google-labs-jules[bot] 4b9763e1da feat: Add problem tracking feature
This commit introduces a new `Problem` model, analogous to `Crop`, to allow users to track problems they have on their plantings (e.g., aphids on tomatoes).

Key features:
- A new `Problem` model that can be curated by admins (`problem_wranglers`).
- Users can associate problems with their plantings and upload photos of the problems.
- Aggregated problem information is displayed on the crop detail page (e.g., "Problems: aphids (27), blight (13)").
- Users can mention problems in posts (e.g., `[aphids](problem)`), which automatically links to the problem's page.
- Admin functionality for reviewing and approving new problem suggestions.

Resolves merge conflict in app/controllers/plantings_controller.rb
2025-09-07 11:47:53 +00:00

89 lines
2.5 KiB
Ruby

# frozen_string_literal: true
class Problem < ApplicationRecord
extend FriendlyId
include PhotoCapable
include SearchCrops # Note: This might need to be adapted to SearchProblems
friendly_id :name, use: %i(slugged finders)
##
## Relationships
belongs_to :creator, class_name: 'Member', optional: true, inverse_of: :created_problems
belongs_to :requester, class_name: 'Member', optional: true, inverse_of: :requested_problems
has_many :planting_problems, dependent: :delete_all
has_many :plantings, through: :planting_problems
has_many :problem_posts, dependent: :delete_all
has_many :posts, through: :problem_posts, dependent: :delete_all
##
## Scopes
scope :recent, -> { approved.order(created_at: :desc) }
scope :popular, -> { approved.order(Arel.sql("plantings_count desc, lower(name) asc")) }
scope :pending_approval, -> { where(approval_status: "pending") }
scope :approved, -> { where(approval_status: "approved") }
scope :rejected, -> { where(approval_status: "rejected") }
scope :interesting, -> { approved.has_photos }
scope :has_photos, -> { includes(:photos).where.not(photos: { id: nil }) }
##
## Validations
validates :reason_for_rejection, presence: true, if: :rejected?
validate :must_be_rejected_if_rejected_reasons_present
validate :must_have_meaningful_reason_for_rejection
validates :name, uniqueness: { scope: :approval_status }, if: :pending?
def to_s
name
end
def to_param
slug
end
def pending?
approval_status == "pending"
end
def approved?
approval_status == "approved"
end
def rejected?
approval_status == "rejected"
end
def approval_statuses
%w(rejected pending approved)
end
def reasons_for_rejection
["already in database", "not a pest or disease", "not enough information", "other"]
end
def rejection_explanation
return rejection_notes if reason_for_rejection == "other"
reason_for_rejection
end
def self.case_insensitive_name(name)
where(["lower(problems.name) = :value", { value: name.downcase }])
end
private
def must_be_rejected_if_rejected_reasons_present
return if rejected?
return unless reason_for_rejection.present? || rejection_notes.present?
errors.add(:approval_status, "must be rejected if a reason for rejection is present")
end
def must_have_meaningful_reason_for_rejection
return unless reason_for_rejection == "other" && rejection_notes.blank?
errors.add(:rejection_notes, "must be added if the reason for rejection is \"other\"")
end
end