Files
growstuff/app/controllers/crops_controller.rb
google-labs-jules[bot] 31c72799ea feat: Add missing public food key id to data improvement page
This change adds a new tab to the data improvement page to show crops that are missing a public food key id.

I was unable to run tests or perform frontend verification due to a known issue with the Ruby environment.
2025-12-01 11:04:01 +00:00

258 lines
7.4 KiB
Ruby

# frozen_string_literal: true
require 'will_paginate/array'
class CropsController < ApplicationController
before_action :authenticate_member!, except: %i(index hierarchy search show)
load_and_authorize_resource id_param: :slug
skip_authorize_resource only: %i(hierarchy search)
respond_to :html, :json, :rss, :csv, :svg
responders :flash
def index
@crops = Crop.search('*', boost_by: %i(plantings_count harvests_count),
limit: 100,
page: params[:page],
load: false)
@num_requested_crops = requested_crops.size if current_member
@filename = filename
respond_with @crops
end
def requested
@requested = requested_crops.paginate(page: params[:page])
respond_with @requested
end
def wrangle
@approval_status = params[:approval_status]
@crops = case @approval_status
when "pending"
Crop.pending_approval
when "rejected"
Crop.rejected
else
Crop.recent
end.paginate(page: params[:page])
@crop_wranglers = Role.crop_wranglers
respond_with @crops
end
def gbif
@crop = Crop.find(params[:crop_slug])
@crop.update_gbif_data!
respond_with @crop, location: @crop
end
def hierarchy
@crops = Crop.toplevel.order(:name)
respond_with @crops
end
def search
@term = params[:term]
@crops = CropSearchService.search(@term,
page: params[:page],
per_page: Crop.per_page,
current_member:)
respond_to do |format|
format.html do
render
end
format.json do
render json: @crops.to_a
end
end
end
def show
respond_to do |format|
format.html do
@posts = @crop.posts.order(created_at: :desc).paginate(page: params[:page])
@companions = @crop.companions.approved
member_ids = @crop.versions.map(&:whodunnit).compact.map(&:to_i)
@version_members = Member.where(id: member_ids).index_by(&:id)
end
format.svg do
icon_data = @crop.svg_icon.presence || File.read(Rails.root.join("app/assets/images/icons/sprout.svg"))
send_data(icon_data, type: "image/svg+xml", disposition: "inline")
end
format.json do
render json: @crop.to_json(crop_json_fields)
end
end
end
def new
@crop = Crop.new
@crop.alternate_names.build
@crop.scientific_names.build
respond_with @crop
end
def edit
@crop.alternate_names.build if @crop.alternate_names.blank?
@crop.scientific_names.build if @crop.scientific_names.blank?
end
def create
@crop = Crop.new(crop_params)
if current_member.role? :crop_wrangler
@crop.creator = current_member
else
@crop.requester = current_member
@crop.approval_status = "pending"
end
if Crop.transaction { @crop.save && save_crop_names }
notify_wranglers
else
@crop.alternate_names.build
@crop.scientific_names.build
end
respond_with @crop
end
def update
if can?(:wrangle, @crop)
@crop.approval_status = 'rejected' if params.fetch("reject", false)
@crop.approval_status = 'approved' if params.fetch("approve", false)
end
@crop.creator = current_member if @crop.approval_status == "pending"
if @crop.update(crop_params)
recreate_names('alt_name', 'alternate')
recreate_names('sci_name', 'scientific')
if @crop.approval_status_changed?(from: "pending", to: "approved")
notifier.deliver_now!
@crop.update_gbif_data!
end
else
@crop.approval_status = @crop.approval_status_was
end
respond_with @crop
end
def destroy
@crop = Crop.find_by!(slug: params[:slug])
authorize! :destroy, @crop
@crop.destroy
respond_with @crop
end
def data_improvement
@active_tab = params[:tab] || 'photos'
@crops = case @active_tab
when 'photos'
Crop.approved.where(photo_associations_count: 0).order(plantings_count: :desc)
when 'descriptions'
Crop.approved.where(description: [nil, '']).order(plantings_count: :desc)
when 'youtube'
Crop.approved.where(en_youtube_url: [nil, '']).order(plantings_count: :desc)
when 'alternate_names'
Crop.approved.left_joins(:alternate_names).where(alternate_names: { id: nil }).order(plantings_count: :desc)
when 'wikidata'
crops_with_wikidata = Crop.joins(:scientific_names).where.not(scientific_names: { wikidata_id: nil }).distinct
Crop.approved.where.not(id: crops_with_wikidata).order(plantings_count: :desc)
when 'row_spacing'
Crop.approved.where(row_spacing: nil).order(plantings_count: :desc)
when 'sun_requirements'
Crop.approved.where(sun_requirements: [nil, '']).order(plantings_count: :desc)
when 'height'
Crop.approved.where(height: nil).order(plantings_count: :desc)
when 'public_food_key'
Crop.approved.where(public_food_key: [nil, '']).order(plantings_count: :desc)
else
Crop.none
end
end
private
def notifier
case @crop.approval_status
when "approved"
NotifierMailer.crop_request_approved(@crop.requester, @crop)
when "rejected"
NotifierMailer.crop_request_rejected(@crop.requester, @crop)
end
end
def save_crop_names
AlternateName.create!(names_params(:alt_name).map { |n| { name: n, creator_id: current_member.id, crop_id: @crop.id, language: "EN" } })
ScientificName.create!(names_params(:sci_name).map { |n| { name: n, creator_id: current_member.id, crop_id: @crop.id } })
end
def notify_wranglers
return if current_member.role? :crop_wrangler
Role.crop_wranglers&.each do |w|
NotifierMailer.new_crop_request(w, @crop).deliver_now!
end
end
def recreate_names(param_name, name_type)
return if params[param_name].blank?
@crop.send("#{name_type}_names").each(&:destroy)
params[param_name].each_value do |value|
next if value.empty?
if name_type == 'alternate'
@crop.send("#{name_type}_names").create!(name: value, creator_id: current_member.id, language: "EN")
else
@crop.send("#{name_type}_names").create!(name: value, creator_id: current_member.id)
end
end
end
def crop_params
params.require(:crop).permit(
:name, :en_wikipedia_url, :en_youtube_url,
:parent_id, :perennial,
:request_notes, :reason_for_rejection,
:rejection_notes,
:description,
:public_food_key,
:row_spacing, :spread, :height,
:sowing_method, :sun_requirements, :growing_degree_days,
scientific_names_attributes: %i(scientific_name _destroy id)
)
end
def names_params(name_type)
params.require(name_type).values&.reject { |n| n.empty? }
end
def filename
"Growstuff-Crops-#{Time.zone.now.to_fs(:number)}.csv"
end
def crop_json_fields
{
include: {
plantings: {
include: {
owner: { only: %i(id login_name location latitude longitude) }
}
},
scientific_names: { only: [:name] }, alternate_names: { only: %i(name language) }
}
}
end
def requested_crops
current_member.requested_crops.pending_approval
end
end