diff --git a/app/controllers/analyze_controller.rb b/app/controllers/analyze_controller.rb index 8e963eb6..e83f32c3 100644 --- a/app/controllers/analyze_controller.rb +++ b/app/controllers/analyze_controller.rb @@ -2,7 +2,8 @@ class AnalyzeController < SqmApplicationController before_action :assign_categories, :assign_subcategories, :assign_measures, :assign_academic_years, - :response_rate_timestamp, :races, :selected_races, :graph, :graphs, :background, :race_score_timestamp, only: [:index] + :response_rate_timestamp, :races, :selected_races, :graph, :graphs, :background, :race_score_timestamp, + :sources, :group, :groups, :selected_grades, :grades, :slice, only: [:index] def index; end private @@ -67,14 +68,15 @@ class AnalyzeController < SqmApplicationController def graph graphs.each do |graph| - @graph = graph if graph.value == params[:graph] + @graph = graph if graph.slug == params[:graph] end @graph ||= graphs.first end def graphs - @graphs ||= [Analyze::Graph::StudentsAndTeachers.new, Analyze::Graph::StudentsByGroup.new(races: selected_races)] + @graphs ||= [Analyze::Graph::StudentsAndTeachers.new, Analyze::Graph::StudentsByRace.new(races: selected_races), + Analyze::Graph::StudentsByGrade.new(grades: selected_grades)] end def background @@ -88,4 +90,61 @@ class AnalyzeController < SqmApplicationController score.updated_at end end + + def sources + @sources = [Analyze::Source::SurveyData.new(slices:)] + end + + def slices + students_and_teachers = Analyze::Slice::StudentsAndTeachers.new + students_by_group = Analyze::Slice::StudentsByGroup.new(races:, grades:) + [students_and_teachers, students_by_group] + end + + def group + groups.each do |group| + @group = group if group.slug == params[:group] + end + + @group ||= groups.first + end + + def groups + @groups = [Analyze::Group::Race.new, Analyze::Group::Grade.new] + end + + def selected_grades + @selected_grades ||= begin + grade_params = params[:grades] + return @selected_grades = grades unless grade_params + + grade_list = grade_params.split(',') if grade_params + if grade_list + grade_list = grade_list.map do |grade| + grade.to_i + end + end + grade_list + end + end + + def grades + @grades ||= SurveyItemResponse.where(school: @school, academic_year: @academic_year) + .where.not(grade: nil) + .group(:grade) + .select(:response_id) + .distinct(:response_id) + .count.reject do |_key, value| + value < 10 + end.keys + end + + def slice + slice_param = params[:slice] + slices.each do |slice| + @slice = slice if slice.slug == slice_param + end + + @slice ||= slices.first + end end diff --git a/app/javascript/controllers/analyze_controller.js b/app/javascript/controllers/analyze_controller.js index 4efa653b..9276a693 100644 --- a/app/javascript/controllers/analyze_controller.js +++ b/app/javascript/controllers/analyze_controller.js @@ -10,10 +10,16 @@ export default class extends Controller { base_url + "&academic_years=" + this.selected_years().join(",") + + "&group=" + + this.selected_group() + + "&slice=" + + this.selected_slice() + "&graph=" + this.selected_graph() + "&races=" + - this.selected_races().join(","); + this.selected_races().join(",") + + "&grades=" + + this.selected_grades().join(","); this.go_to(url); } @@ -36,17 +42,50 @@ export default class extends Controller { return years; } + selected_group() { + let groups = [...document.getElementsByName("group-option")]; + let selected_group = groups + .filter((item) => { + return item.selected; + }) + .map((item) => { + return item.id; + }); + + return selected_group[0]; + } + + selected_slice() { + let slices = [...document.getElementsByName("slice")]; + let selected_slice = slices + .filter((item) => { + return item.checked; + }) + .map((item) => { + return item.id; + }); + + return selected_slice[0]; + } + selected_graph() { - let graphs = [...document.getElementsByName("graph")]; + let graphs = [...document.getElementsByName("slice")]; let selected_graph = graphs .filter((item) => { return item.checked; }) .map((item) => { return item.id; - }); + })[0]; + if (selected_graph === 'students-and-teachers') { + return selected_graph; + } - return selected_graph[0]; + if (this.selected_group() === 'race') { + return 'students-by-race' + } else { + return 'students-by-grade' + } } selected_races() { @@ -61,4 +100,17 @@ export default class extends Controller { return races; } + + selected_grades() { + let grade_checkboxes = [...document.getElementsByName("grade-checkbox")] + let grades = grade_checkboxes + .filter((item) => { + return item.checked; + }) + .map((item) => { + return item.id.replace('grade-', ''); + }); + + return grades; + } } diff --git a/app/models/measure.rb b/app/models/measure.rb index e950d35d..419be2fa 100644 --- a/app/models/measure.rb +++ b/app/models/measure.rb @@ -145,7 +145,7 @@ class Measure < ActiveRecord::Base meets_student_threshold = sufficient_student_data?(school:, academic_year:) meets_teacher_threshold = sufficient_teacher_data?(school:, academic_year:) meets_admin_data_threshold = any_admin_data_collected?(school:, academic_year:) - Score.new(average, meets_teacher_threshold, meets_student_threshold, meets_admin_data_threshold) + Score.new(average:, meets_teacher_threshold:, meets_student_threshold:, meets_admin_data_threshold:) end def collect_survey_item_average(survey_items:, school:, academic_year:) diff --git a/app/models/score.rb b/app/models/score.rb index eba18591..ca355125 100644 --- a/app/models/score.rb +++ b/app/models/score.rb @@ -1,7 +1,20 @@ # frozen_string_literal: true -class Score < Struct.new(:average, :meets_teacher_threshold?, :meets_student_threshold?, :meets_admin_data_threshold?) - NIL_SCORE = Score.new(nil, false, false, false) +class Score < ApplicationRecord + belongs_to :measure + belongs_to :school + belongs_to :academic_year + belongs_to :race + + NIL_SCORE = Score.new(average: nil, meets_teacher_threshold: false, meets_student_threshold: false, meets_admin_data_threshold: false) + + enum group: { + all_students: 0, + race: 1, + grade: 2, + gender: 3 + } + def in_zone?(zone:) return false if average.nil? || average.is_a?(Float) && average.nan? diff --git a/app/models/survey_item_response.rb b/app/models/survey_item_response.rb index f721a512..32a77885 100644 --- a/app/models/survey_item_response.rb +++ b/app/models/survey_item_response.rb @@ -15,4 +15,10 @@ class SurveyItemResponse < ActiveRecord::Base boston = District.find_by_name('Boston') where.not(school: boston.schools) if boston.present? } + + scope :averages_for_grade, ->(survey_items, school, academic_year, grade) { + SurveyItemResponse.where(survey_item: survey_items, school:, + academic_year: , grade:).group(:survey_item).average(:likert_score) + } + end diff --git a/app/presenters/analyze/graph/column/grade/eight.rb b/app/presenters/analyze/graph/column/grade/eight.rb new file mode 100644 index 00000000..530fada1 --- /dev/null +++ b/app/presenters/analyze/graph/column/grade/eight.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module Analyze + module Graph + module Column + module Grade + class Eight < GroupedBarColumnPresenter + include Analyze::Graph::Column::Grade::ScoreForGrade + def label + 'Grade 8' + end + + def basis + 'student' + end + + def show_irrelevancy_message? + false + end + + def show_insufficient_data_message? + false + end + + def grade + 8 + end + end + end + end + end +end + diff --git a/app/presenters/analyze/graph/column/grade/eleven.rb b/app/presenters/analyze/graph/column/grade/eleven.rb new file mode 100644 index 00000000..45dd257b --- /dev/null +++ b/app/presenters/analyze/graph/column/grade/eleven.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module Analyze + module Graph + module Column + module Grade + class Eleven < GroupedBarColumnPresenter + include Analyze::Graph::Column::Grade::ScoreForGrade + def label + 'Grade 11' + end + + def basis + 'student' + end + + def show_irrelevancy_message? + false + end + + def show_insufficient_data_message? + false + end + + def grade + 11 + end + end + end + end + end +end + diff --git a/app/presenters/analyze/graph/column/grade/five.rb b/app/presenters/analyze/graph/column/grade/five.rb new file mode 100644 index 00000000..b6f2f5e3 --- /dev/null +++ b/app/presenters/analyze/graph/column/grade/five.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Analyze + module Graph + module Column + module Grade + class Five < GroupedBarColumnPresenter + include Analyze::Graph::Column::Grade::ScoreForGrade + def label + 'Grade 5' + end + + def basis + 'student' + end + + def show_irrelevancy_message? + false + end + + def show_insufficient_data_message? + false + end + + def grade + 5 + end + end + end + end + end +end diff --git a/app/presenters/analyze/graph/column/grade/four.rb b/app/presenters/analyze/graph/column/grade/four.rb new file mode 100644 index 00000000..ce1be6b3 --- /dev/null +++ b/app/presenters/analyze/graph/column/grade/four.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Analyze + module Graph + module Column + module Grade + class Four < GroupedBarColumnPresenter + include Analyze::Graph::Column::Grade::ScoreForGrade + def label + 'Grade 4' + end + + def basis + 'student' + end + + def show_irrelevancy_message? + false + end + + def show_insufficient_data_message? + false + end + + def grade + 4 + end + end + end + end + end +end diff --git a/app/presenters/analyze/graph/column/grade/nine.rb b/app/presenters/analyze/graph/column/grade/nine.rb new file mode 100644 index 00000000..9a3f91d8 --- /dev/null +++ b/app/presenters/analyze/graph/column/grade/nine.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module Analyze + module Graph + module Column + module Grade + class Nine < GroupedBarColumnPresenter + include Analyze::Graph::Column::Grade::ScoreForGrade + def label + 'Grade 9' + end + + def basis + 'student' + end + + def show_irrelevancy_message? + false + end + + def show_insufficient_data_message? + false + end + + def grade + 9 + end + end + end + end + end +end + + diff --git a/app/presenters/analyze/graph/column/grade/one.rb b/app/presenters/analyze/graph/column/grade/one.rb new file mode 100644 index 00000000..3e6d1367 --- /dev/null +++ b/app/presenters/analyze/graph/column/grade/one.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Analyze + module Graph + module Column + module Grade + class One < GroupedBarColumnPresenter + include Analyze::Graph::Column::Grade::ScoreForGrade + def label + 'Grade 1' + end + + def basis + 'student' + end + + def show_irrelevancy_message? + false + end + + def show_insufficient_data_message? + false + end + + def grade + 1 + end + end + end + 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 new file mode 100644 index 00000000..f6434dc8 --- /dev/null +++ b/app/presenters/analyze/graph/column/grade/score_for_grade.rb @@ -0,0 +1,27 @@ +module Analyze + module Graph + module Column + module Grade + module ScoreForGrade + def score(year_index) + averages = SurveyItemResponse.averages_for_grade(measure.student_survey_items, school, academic_years[year_index], grade) + average = bubble_up_averages(averages:) + + Score.new(average:, + meets_teacher_threshold: false, + meets_student_threshold: true, + meets_admin_data_threshold: false) + end + + def bubble_up_averages(averages:) + measure.student_scales.map do |scale| + scale.survey_items.map do |survey_item| + averages[survey_item] + end.remove_blanks.average + end.remove_blanks.average + end + end + end + end + end +end diff --git a/app/presenters/analyze/graph/column/grade/seven.rb b/app/presenters/analyze/graph/column/grade/seven.rb new file mode 100644 index 00000000..ae82b562 --- /dev/null +++ b/app/presenters/analyze/graph/column/grade/seven.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Analyze + module Graph + module Column + module Grade + class Seven < GroupedBarColumnPresenter + include Analyze::Graph::Column::Grade::ScoreForGrade + def label + 'Grade 7' + end + + def basis + 'student' + end + + def show_irrelevancy_message? + false + end + + def show_insufficient_data_message? + false + end + + def grade + 7 + end + end + end + end + end +end diff --git a/app/presenters/analyze/graph/column/grade/six.rb b/app/presenters/analyze/graph/column/grade/six.rb new file mode 100644 index 00000000..d6aadba9 --- /dev/null +++ b/app/presenters/analyze/graph/column/grade/six.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Analyze + module Graph + module Column + module Grade + class Six < GroupedBarColumnPresenter + include Analyze::Graph::Column::Grade::ScoreForGrade + def label + 'Grade 6' + end + + def basis + 'student' + end + + def show_irrelevancy_message? + false + end + + def show_insufficient_data_message? + false + end + + def grade + 6 + end + end + end + end + end +end diff --git a/app/presenters/analyze/graph/column/grade/ten.rb b/app/presenters/analyze/graph/column/grade/ten.rb new file mode 100644 index 00000000..9224881b --- /dev/null +++ b/app/presenters/analyze/graph/column/grade/ten.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module Analyze + module Graph + module Column + module Grade + class Ten < GroupedBarColumnPresenter + include Analyze::Graph::Column::Grade::ScoreForGrade + def label + 'Grade 10' + end + + def basis + 'student' + end + + def show_irrelevancy_message? + false + end + + def show_insufficient_data_message? + false + end + + def grade + 10 + end + end + end + end + end +end + + diff --git a/app/presenters/analyze/graph/column/grade/three.rb b/app/presenters/analyze/graph/column/grade/three.rb new file mode 100644 index 00000000..570664da --- /dev/null +++ b/app/presenters/analyze/graph/column/grade/three.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Analyze + module Graph + module Column + module Grade + class Three < GroupedBarColumnPresenter + include Analyze::Graph::Column::Grade::ScoreForGrade + def label + 'Grade 3' + end + + def basis + 'student' + end + + def show_irrelevancy_message? + false + end + + def show_insufficient_data_message? + false + end + + def grade + 3 + end + end + end + end + end +end diff --git a/app/presenters/analyze/graph/column/grade/twelve.rb b/app/presenters/analyze/graph/column/grade/twelve.rb new file mode 100644 index 00000000..52ec06e9 --- /dev/null +++ b/app/presenters/analyze/graph/column/grade/twelve.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module Analyze + module Graph + module Column + module Grade + class Twelve < GroupedBarColumnPresenter + include Analyze::Graph::Column::Grade::ScoreForGrade + def label + 'Grade 12' + end + + def basis + 'student' + end + + def show_irrelevancy_message? + false + end + + def show_insufficient_data_message? + false + end + + def grade + 12 + end + end + end + end + end +end + + diff --git a/app/presenters/analyze/graph/column/grade/two.rb b/app/presenters/analyze/graph/column/grade/two.rb new file mode 100644 index 00000000..c2541d6b --- /dev/null +++ b/app/presenters/analyze/graph/column/grade/two.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module Analyze + module Graph + module Column + module Grade + class Two < GroupedBarColumnPresenter + attr_reader :sufficient_responses + + include Analyze::Graph::Column::Grade::ScoreForGrade + def label + 'Grade 2' + end + + def basis + 'student' + end + + def show_irrelevancy_message? + false + end + + def show_insufficient_data_message? + false + end + + def grade + 2 + end + end + end + end + end +end diff --git a/app/presenters/analyze/graph/column/score_for_race.rb b/app/presenters/analyze/graph/column/score_for_race.rb index c4cbb0c0..5fd661d3 100644 --- a/app/presenters/analyze/graph/column/score_for_race.rb +++ b/app/presenters/analyze/graph/column/score_for_race.rb @@ -8,7 +8,10 @@ module Analyze average ||= 0 meets_student_threshold = s.meets_student_threshold? unless s.nil? meets_student_threshold ||= false - Score.new(average, false, meets_student_threshold, false) + Score.new(average:, + meets_teacher_threshold: false, + meets_student_threshold:, + meets_admin_data_threshold: false) end end end diff --git a/app/models/analyze/graph/students_and_teachers.rb b/app/presenters/analyze/graph/students_and_teachers.rb similarity index 95% rename from app/models/analyze/graph/students_and_teachers.rb rename to app/presenters/analyze/graph/students_and_teachers.rb index bb21052e..dc6f394d 100644 --- a/app/models/analyze/graph/students_and_teachers.rb +++ b/app/presenters/analyze/graph/students_and_teachers.rb @@ -8,7 +8,7 @@ module Analyze 'Students & Teachers' end - def value + def slug 'students-and-teachers' end diff --git a/app/presenters/analyze/graph/students_by_grade.rb b/app/presenters/analyze/graph/students_by_grade.rb new file mode 100644 index 00000000..4330e012 --- /dev/null +++ b/app/presenters/analyze/graph/students_by_grade.rb @@ -0,0 +1,50 @@ +module Analyze + module Graph + class StudentsByGrade + include Analyze::Graph::Column::Grade + attr_reader :grades + + def initialize(grades:) + @grades = grades + end + + def to_s + 'Students by Grade' + end + + def slug + 'students-by-grade' + end + + def columns + [].tap do |array| + grades.each do |grade| + array << column_for_grade_code(code: grade) + end + array << Analyze::Graph::Column::AllStudent + end + end + + private + + def column_for_grade_code(code:) + CFR[code] + end + + CFR = { + 1 => One, + 2 => Two, + 3 => Three, + 4 => Four, + 5 => Five, + 6 => Six, + 7 => Seven, + 8 => Eight, + 9 => Nine, + 10 => Ten, + 11 => Eleven, + 12 => Twelve, + }.freeze + end + end +end diff --git a/app/models/analyze/graph/students_by_group.rb b/app/presenters/analyze/graph/students_by_race.rb similarity index 89% rename from app/models/analyze/graph/students_by_group.rb rename to app/presenters/analyze/graph/students_by_race.rb index d81b036d..7f077741 100644 --- a/app/models/analyze/graph/students_by_group.rb +++ b/app/presenters/analyze/graph/students_by_race.rb @@ -1,6 +1,6 @@ module Analyze module Graph - class StudentsByGroup + class StudentsByRace attr_reader :races def initialize(races:) @@ -8,11 +8,11 @@ module Analyze end def to_s - 'Students by Group' + 'Students by Race' end - def value - 'students-by-group' + def slug + 'students-by-race' end def columns @@ -39,7 +39,7 @@ module Analyze '8' => Analyze::Graph::Column::MiddleEastern, '99' => Analyze::Graph::Column::Unknown, '100' => Analyze::Graph::Column::Multiracial - } + }.freeze end end end diff --git a/app/presenters/analyze/group/grade.rb b/app/presenters/analyze/group/grade.rb new file mode 100644 index 00000000..9504469c --- /dev/null +++ b/app/presenters/analyze/group/grade.rb @@ -0,0 +1,13 @@ +module Analyze + module Group + class Grade + def name + 'Grade' + end + + def slug + 'grade' + end + end + end +end diff --git a/app/presenters/analyze/group/race.rb b/app/presenters/analyze/group/race.rb new file mode 100644 index 00000000..1155d1c4 --- /dev/null +++ b/app/presenters/analyze/group/race.rb @@ -0,0 +1,13 @@ +module Analyze + module Group + class Race + def name + 'Race' + end + + def slug + 'race' + end + end + end +end diff --git a/app/presenters/analyze/slice/students_and_teachers.rb b/app/presenters/analyze/slice/students_and_teachers.rb new file mode 100644 index 00000000..75eb921b --- /dev/null +++ b/app/presenters/analyze/slice/students_and_teachers.rb @@ -0,0 +1,17 @@ +module Analyze + module Slice + class StudentsAndTeachers + def to_s + 'Students & Teachers' + end + + def slug + 'students-and-teachers' + end + + def graphs + [Analyze::Graph::StudentsAndTeachers.new] + end + end + end +end diff --git a/app/presenters/analyze/slice/students_by_group.rb b/app/presenters/analyze/slice/students_by_group.rb new file mode 100644 index 00000000..af62be61 --- /dev/null +++ b/app/presenters/analyze/slice/students_by_group.rb @@ -0,0 +1,24 @@ +module Analyze + module Slice + class StudentsByGroup + attr_reader :races, :grades + + def initialize(races:, grades:) + @races = races + @grades = grades + end + + def to_s + 'Students by Group' + end + + def slug + 'students-by-group' + end + + def graphs + [Analyze::Graph::StudentsByRace.new(races:), Analyze::Graph::StudentsByGrade.new(grades:)] + end + end + end +end diff --git a/app/presenters/analyze/source/survey_data.rb b/app/presenters/analyze/source/survey_data.rb new file mode 100644 index 00000000..1cef340a --- /dev/null +++ b/app/presenters/analyze/source/survey_data.rb @@ -0,0 +1,20 @@ +module Analyze + module Source + class SurveyData + attr_reader :slices + + include Analyze::Slice + + def initialize(slices:) + @slices = slices + end + # def to_s + # 'Survey Data Only' + # end + + # def value + # 'survey-data-only' + # end + end + end +end diff --git a/app/presenters/zones.rb b/app/presenters/zones.rb index 50987a7d..91c63d94 100644 --- a/app/presenters/zones.rb +++ b/app/presenters/zones.rb @@ -42,6 +42,6 @@ class Zones end def zone_for_score(score) - all_zones.find { |zone| Score.new(score).in_zone?(zone:) } || insufficient_data + all_zones.find { |zone| Score.new(average: score).in_zone?(zone:) } || insufficient_data end end diff --git a/app/services/race_score_loader.rb b/app/services/race_score_loader.rb index da043164..f7512fc8 100644 --- a/app/services/race_score_loader.rb +++ b/app/services/race_score_loader.rb @@ -45,15 +45,13 @@ class RaceScoreLoader def self.race_score(measure:, school:, academic_year:, race:) rate = response_rate(school:, academic_year:, measure:) - return Score.new(0, false, false, false) unless rate.meets_student_threshold + return Score.new(average: 0, meets_teacher_threshold: false, meets_student_threshold: false, meets_admin_data_threshold: false) unless rate.meets_student_threshold survey_items = measure.student_survey_items - # students = StudentRace.where(race:).pluck(:student_id).uniq 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:) - # binding.break end def self.grouped_responses(school:, academic_year:, survey_items:, race:) @@ -83,7 +81,7 @@ class RaceScoreLoader average = 0 unless meets_student_threshold - Score.new(average, false, meets_student_threshold, false) + Score.new(average:, meets_teacher_threshold: false, meets_student_threshold:, meets_admin_data_threshold: false) end def self.sufficient_responses(school:, academic_year:, race:) diff --git a/app/services/survey_responses_data_loader.rb b/app/services/survey_responses_data_loader.rb index 852a513a..55e836d6 100644 --- a/app/services/survey_responses_data_loader.rb +++ b/app/services/survey_responses_data_loader.rb @@ -6,11 +6,10 @@ class SurveyResponsesDataLoader def self.load_data(filepath:) File.open(filepath) do |file| headers = file.first - survey_items = SurveyItem.where(survey_item_id: get_survey_item_ids_from_headers(headers:)) file.lazy.each_slice(1000) do |lines| survey_item_responses = CSV.parse(lines.join, headers:).map do |row| - process_row row: row, survey_items: survey_items + process_row row: Values.new(row:, headers:) end SurveyItemResponse.import survey_item_responses.compact.flatten, batch_size: 1000 @@ -20,89 +19,102 @@ class SurveyResponsesDataLoader private - def self.process_row(row:, survey_items:) - id = dese_id(row) - return unless dese_id?(id) + def self.process_row(row:) + return unless row.dese_id? + return unless row.school.present? - school = School.find_by_dese_id(id) - return unless school.present? - - process_survey_items(row:, survey_items:, school:) + process_survey_items(row:) end - def self.process_survey_items(row:, survey_items:, school:) - id = response_id(row) - survey_items.map do |survey_item| - likert_score = row[survey_item.survey_item_id] || next + def self.process_survey_items(row:) + row.survey_items.map do |survey_item| + likert_score = row.likert_score(survey_item_id: survey_item.survey_item_id) || next unless likert_score.valid_likert_score? - puts "Response ID: #{id}, Likert score: #{likert_score} rejected" unless likert_score == 'NA' + puts "Response ID: #{row.response_id}, Likert score: #{likert_score} rejected" unless likert_score == 'NA' next end - response = survey_item_response(response_id: id, survey_item:) - create_or_update_response(survey_item_response: response, likert_score:, school:, row:, survey_item:) + response = row.survey_item_response(survey_item:) + create_or_update_response(survey_item_response: response, likert_score:, row:, survey_item:) end.compact end - def self.create_or_update_response(survey_item_response:, likert_score:, school:, row:, survey_item:) + def self.create_or_update_response(survey_item_response:, likert_score:, row:, survey_item:) if survey_item_response.present? - survey_item_response.update!(likert_score:) if survey_item_response.likert_score != likert_score + survey_item_response.update!(likert_score:) [] else - SurveyItemResponse.new(response_id: response_id(row), academic_year: academic_year(row), school:, survey_item:, - likert_score:) + SurveyItemResponse.new(response_id: row.response_id, academic_year: row.academic_year, school: row.school, survey_item:, + likert_score:, grade: row.grade) end end - def self.get_survey_item_ids_from_headers(headers:) - CSV.parse(headers, headers: true).headers - .filter(&:present?) - .filter { |header| header.start_with? 't-' or header.start_with? 's-' } + private_class_method :process_row + private_class_method :process_survey_items + private_class_method :create_or_update_response +end + +class Values + attr_reader :row, :headers + + def initialize(row:, headers:) + @row = row + @headers = headers end - def self.dese_id?(dese_id) + def dese_id? dese_id.present? end - def self.response_date(row) - Date.parse(row['Recorded Date'] || row['RecordedDate']) + def response_date + @response_date ||= Date.parse(row['Recorded Date'] || row['RecordedDate']) end - def self.academic_year(row) - AcademicYear.find_by_date response_date(row) + def academic_year + @academic_year ||= AcademicYear.find_by_date response_date end - def self.survey_item_response(response_id:, survey_item:) + def survey_item_response(survey_item:) SurveyItemResponse.find_by(response_id:, survey_item:) end - def self.response_id(row) - row['Response ID'] || row['ResponseId'] || row['ResponseID'] + def response_id + @response_id ||= row['Response ID'] || row['ResponseId'] || row['ResponseID'] end - def self.dese_id(row) - row['DESE ID' || 'Dese ID'] || row['DeseId'] || row['DeseID'] + def dese_id + @dese_id ||= (row['DESE ID' || 'Dese ID'] || row['DeseId'] || row['DeseID']).to_i end - private_class_method :process_row - private_class_method :process_survey_items - private_class_method :get_survey_item_ids_from_headers - private_class_method :dese_id? - private_class_method :create_or_update_response - private_class_method :response_date - private_class_method :academic_year - private_class_method :survey_item_response - private_class_method :response_id - private_class_method :dese_id -end + def likert_score(survey_item_id:) + row[survey_item_id] + end -module StringMonkeyPatches - def integer? - to_i.to_s == self + def school + @school ||= School.find_by_dese_id(dese_id) + end + + def survey_items + @survey_items ||= SurveyItem.where(survey_item_id: get_survey_item_ids_from_headers(headers:)) + end + + def get_survey_item_ids_from_headers(headers:) + CSV.parse(headers, headers: true).headers + .filter(&:present?) + .filter { |header| header.start_with? 't-' or header.start_with? 's-' } end + def grade + @grade ||= begin + raw_grade = (row['grade'] || row['Grade'] || row['What grade are you in?']).to_i + raw_grade == 0 ? nil : raw_grade + end + end +end + +module StringMonkeyPatches def valid_likert_score? - integer? and to_i.between? 1, 5 + to_i.between? 1, 5 end end diff --git a/app/views/analyze/_data_filters.html.erb b/app/views/analyze/_data_filters.html.erb index b7d5f95e..df616ea9 100644 --- a/app/views/analyze/_data_filters.html.erb +++ b/app/views/analyze/_data_filters.html.erb @@ -1,23 +1,28 @@ -<%# TODO Hook up the buttons so that only the selected races are shown for each column %>
Select a group
<% @races.each do |race | %> -