diff --git a/app/models/survey_item_response.rb b/app/models/survey_item_response.rb index b54bb35b..21f05887 100644 --- a/app/models/survey_item_response.rb +++ b/app/models/survey_item_response.rb @@ -19,16 +19,22 @@ class SurveyItemResponse < ActiveRecord::Base scope :averages_for_grade, lambda { |survey_items, school, academic_year, grade| SurveyItemResponse.where(survey_item: survey_items, school:, - academic_year:, grade:).group(:survey_item).average(:likert_score) + academic_year:, grade:).group(:survey_item).having("count(*) >= 10").average(:likert_score) } scope :averages_for_gender, lambda { |survey_items, school, academic_year, gender| SurveyItemResponse.where(survey_item: survey_items, school:, - academic_year:, gender:, grade: school.grades(academic_year:)).group(:survey_item).average(:likert_score) + academic_year:, gender:, grade: school.grades(academic_year:)).group(:survey_item).having("count(*) >= 10").average(:likert_score) } scope :averages_for_income, lambda { |survey_items, school, academic_year, income| SurveyItemResponse.where(survey_item: survey_items, school:, - academic_year:, income:, grade: school.grades(academic_year:)).group(:survey_item).average(:likert_score) + academic_year:, income:, grade: school.grades(academic_year:)).group(:survey_item).having("count(*) >= 10").average(:likert_score) + } + + scope :averages_for_race, lambda { |school, academic_year, race| + SurveyItemResponse.joins("JOIN student_races on survey_item_responses.student_id = student_races.student_id JOIN students on students.id = student_races.student_id").where( + school:, academic_year:, grade: school.grades(academic_year:) + ).where("student_races.race_id": race.id).group(:survey_item_id).having("count(*) >= 10").average(:likert_score) } end diff --git a/app/presenters/analyze/graph/column/gender_column/score_for_gender.rb b/app/presenters/analyze/graph/column/gender_column/score_for_gender.rb index 962f0d7e..2b5e22c4 100644 --- a/app/presenters/analyze/graph/column/gender_column/score_for_gender.rb +++ b/app/presenters/analyze/graph/column/gender_column/score_for_gender.rb @@ -5,11 +5,17 @@ module Analyze module ScoreForGender def score(year_index) academic_year = academic_years[year_index] + meets_student_threshold = sufficient_student_responses?(academic_year:) + return Score::NIL_SCORE unless meets_student_threshold + averages = SurveyItemResponse.averages_for_gender(measure.student_survey_items, school, academic_year, gender) average = bubble_up_averages(averages:).round(2) - scorify(average:, meets_student_threshold: sufficient_student_responses?(academic_year:)) + Score.new(average:, + meets_teacher_threshold: false, + meets_student_threshold:, + meets_admin_data_threshold: false) end def bubble_up_averages(averages:) @@ -20,25 +26,14 @@ module Analyze end.remove_blanks.average end - def scorify(average:, meets_student_threshold:) - return Score::NIL_SCORE unless meets_student_threshold - - Score.new(average:, - meets_teacher_threshold: false, - meets_student_threshold:, - meets_admin_data_threshold: false) - end - def sufficient_student_responses?(academic_year:) - sufficient_overall_responses = measure.subcategory.response_rate(school:, - academic_year:).meets_student_threshold + return false unless measure.subcategory.response_rate(school:, academic_year:).meets_student_threshold? + yearly_counts = SurveyItemResponse.where(school:, academic_year:, gender:, survey_item: measure.student_survey_items).group(:gender).select(:response_id).distinct(:response_id).count - more_than_ten_respondents = yearly_counts.any? do |count| + yearly_counts.any? do |count| count[1] >= 10 end - - sufficient_overall_responses && more_than_ten_respondents end end end diff --git a/app/presenters/analyze/graph/column/grade/score_for_grade.rb b/app/presenters/analyze/graph/column/grade/score_for_grade.rb index c8ab378f..812c9cb9 100644 --- a/app/presenters/analyze/graph/column/grade/score_for_grade.rb +++ b/app/presenters/analyze/graph/column/grade/score_for_grade.rb @@ -5,13 +5,16 @@ module Analyze module ScoreForGrade def score(year_index) academic_year = academic_years[year_index] + meets_student_threshold = sufficient_student_responses?(academic_year:) + return Score::NIL_SCORE unless meets_student_threshold + averages = SurveyItemResponse.averages_for_grade(measure.student_survey_items, school, academic_year, grade) average = bubble_up_averages(averages:).round(2) Score.new(average:, meets_teacher_threshold: false, - meets_student_threshold: sufficient_student_responses?(academic_year:), + meets_student_threshold:, meets_admin_data_threshold: false) end @@ -24,7 +27,13 @@ module Analyze end def sufficient_student_responses?(academic_year:) - measure.subcategory.response_rate(school:, academic_year:).meets_student_threshold + return false unless measure.subcategory.response_rate(school:, academic_year:).meets_student_threshold? + + yearly_counts = SurveyItemResponse.where(school:, academic_year:, + survey_item: measure.student_survey_items).group(:grade).select(:response_id).distinct(:response_id).count + yearly_counts.any? do |count| + count[1] >= 10 + end end end end diff --git a/app/presenters/analyze/graph/column/income_column/score_for_income.rb b/app/presenters/analyze/graph/column/income_column/score_for_income.rb index ff5cf8d1..2be5aa5d 100644 --- a/app/presenters/analyze/graph/column/income_column/score_for_income.rb +++ b/app/presenters/analyze/graph/column/income_column/score_for_income.rb @@ -5,11 +5,17 @@ module Analyze module ScoreForIncome def score(year_index) academic_year = academic_years[year_index] + meets_student_threshold = sufficient_student_responses?(academic_year:) + return Score::NIL_SCORE unless meets_student_threshold + averages = SurveyItemResponse.averages_for_income(measure.student_survey_items, school, academic_year, income) average = bubble_up_averages(averages:).round(2) - scorify(average:, meets_student_threshold: sufficient_student_responses?(academic_year:)) + Score.new(average:, + meets_teacher_threshold: false, + meets_student_threshold:, + meets_admin_data_threshold: false) end def bubble_up_averages(averages:) @@ -20,18 +26,9 @@ module Analyze end.remove_blanks.average end - def scorify(average:, meets_student_threshold:) - return Score::NIL_SCORE unless meets_student_threshold - - Score.new(average:, - meets_teacher_threshold: false, - meets_student_threshold:, - meets_admin_data_threshold: false) - end - def sufficient_student_responses?(academic_year:) - sufficient_overall_responses = measure.subcategory.response_rate(school:, - academic_year:).meets_student_threshold + return false unless measure.subcategory.response_rate(school:, academic_year:).meets_student_threshold? + yearly_counts = SurveyItemResponse.where(school:, academic_year:, income:, survey_item: measure.student_survey_items).group(:income).select(:response_id).distinct(:response_id).count more_than_ten_respondents = yearly_counts.any? do |count| diff --git a/app/presenters/analyze/graph/column/score_for_race.rb b/app/presenters/analyze/graph/column/score_for_race.rb index 36bee8a5..5fdc2e90 100644 --- a/app/presenters/analyze/graph/column/score_for_race.rb +++ b/app/presenters/analyze/graph/column/score_for_race.rb @@ -3,63 +3,36 @@ module Analyze module Column module ScoreForRace def score(year_index) - academic_year = academic_year_for_year_index(year_index) - rate = response_rate(school:, academic_year:, measure:) - return Score::NIL_SCORE unless rate.meets_student_threshold + academic_year = academic_years[year_index] + meets_student_threshold = sufficient_student_responses?(academic_year:) + return Score::NIL_SCORE unless meets_student_threshold survey_items = measure.student_survey_items - averages = grouped_responses(school:, academic_year:, survey_items:, race:) - meets_student_threshold = sufficient_responses(school:, academic_year:, race:) - scorify(responses: averages, meets_student_threshold:, measure:) - end - - def grouped_responses(school:, academic_year:, survey_items:, race:) - @grouped_responses ||= Hash.new do |memo, (school, academic_year, survey_items, race)| - memo[[school, academic_year, survey_items, race]] = - SurveyItemResponse.joins("JOIN student_races on survey_item_responses.student_id = student_races.student_id JOIN students on students.id = student_races.student_id").where( - school:, academic_year:, grade: school.grades(academic_year:) - ).where("student_races.race_id": race.id).group(:survey_item_id).having("count(*) >= 10").average(:likert_score) - end - - @grouped_responses[[school, academic_year, survey_items, race]] - end - - def response_rate(school:, academic_year:, measure:) - subcategory = measure.subcategory - @response_rate ||= Hash.new do |memo, (school, academic_year, subcategory)| - memo[[school, academic_year, subcategory]] = subcategory.response_rate(school:, academic_year:) - end - - @response_rate[[school, academic_year, subcategory]] - end + averages = SurveyItemResponse.averages_for_race(school, academic_year, race) + average = bubble_up_averages(averages:).round(2) - def scorify(responses:, meets_student_threshold:, measure:) - averages = bubble_up_averages(responses:, measure:) - average = averages.average.round(2) - - average = 0 unless meets_student_threshold - - Score.new(average:, meets_teacher_threshold: false, meets_student_threshold:, + Score.new(average:, + meets_teacher_threshold: false, + meets_student_threshold:, meets_admin_data_threshold: false) end - def sufficient_responses(school:, academic_year:, race:) - @sufficient_responses ||= Hash.new do |memo, (school, academic_year, race)| - number_of_students_for_a_racial_group = SurveyItemResponse.joins("JOIN student_races on survey_item_responses.student_id = student_races.student_id JOIN students on students.id = student_races.student_id").where( - school:, academic_year: - ).where("student_races.race_id": race.id).distinct.pluck(:student_id).count - memo[[school, academic_year, race]] = number_of_students_for_a_racial_group >= 10 - end - @sufficient_responses[[school, academic_year, race]] - end - - def bubble_up_averages(responses:, measure:) + def bubble_up_averages(averages:) measure.student_scales.map do |scale| scale.survey_items.map do |survey_item| - responses[survey_item.id] + averages[survey_item.id] end.remove_blanks.average - end.remove_blanks + end.remove_blanks.average + end + + def sufficient_student_responses?(academic_year:) + return false unless measure.subcategory.response_rate(school:, academic_year:).meets_student_threshold? + + number_of_students_for_a_racial_group = SurveyItemResponse.joins("JOIN student_races on survey_item_responses.student_id = student_races.student_id JOIN students on students.id = student_races.student_id").where( + school:, academic_year: + ).where("student_races.race_id": race.id).distinct.pluck(:student_id).count + number_of_students_for_a_racial_group >= 10 end end end diff --git a/app/services/survey_item_values.rb b/app/services/survey_item_values.rb index 54aac257..30b8643b 100644 --- a/app/services/survey_item_values.rb +++ b/app/services/survey_item_values.rb @@ -119,7 +119,6 @@ class SurveyItemValues return @raw_income if @raw_income.present? return "Unknown" unless disaggregation_data.present? - byebug disaggregation = disaggregation_data[[lasid, district.name, academic_year.range]] return "Unknown" unless disaggregation.present?