mirror of
https://github.com/edcommonwealth/sqm-dashboards.git
synced 2026-03-13 09:20:38 -07:00
Refactor based on rubocop and reek suggestions
This commit is contained in:
parent
fc853c4fbc
commit
18b479b8b2
7 changed files with 733 additions and 678 deletions
|
|
@ -1,15 +1,28 @@
|
|||
class AnalyzeController < SqmApplicationController
|
||||
def index
|
||||
assign_categories
|
||||
assign_subcategories
|
||||
assign_measures
|
||||
assign_academic_years
|
||||
end
|
||||
|
||||
def assign_categories
|
||||
@category ||= Category.find_by_category_id(params[:category])
|
||||
@category ||= Category.order(:category_id).first
|
||||
@categories = Category.all.order(:category_id)
|
||||
end
|
||||
|
||||
def assign_subcategories
|
||||
@subcategories = @category.subcategories.order(:subcategory_id)
|
||||
@subcategory ||= Subcategory.find_by_subcategory_id(params[:subcategory])
|
||||
@subcategory ||= @subcategories.first
|
||||
end
|
||||
|
||||
def assign_measures
|
||||
@measures = @subcategory.measures.order(:measure_id).includes(%i[scales admin_data_items subcategory])
|
||||
end
|
||||
|
||||
def assign_academic_years
|
||||
@available_academic_years = AcademicYear.order(:range).all
|
||||
@academic_year_params = params[:academic_years].split(',') if params[:academic_years]
|
||||
@selected_academic_years = []
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Measure < ActiveRecord::Base
|
||||
belongs_to :subcategory, counter_cache: true
|
||||
has_one :category, through: :subcategory
|
||||
|
|
@ -24,9 +26,9 @@ class Measure < ActiveRecord::Base
|
|||
|
||||
def student_survey_items_by_survey_type(school:, academic_year:)
|
||||
survey = Survey.where(school:, academic_year:).first
|
||||
return survey_items.student_survey_items.short_form_items if survey.form == 'short'
|
||||
return student_survey_items.short_form_items if survey.form == 'short'
|
||||
|
||||
survey_items.student_survey_items
|
||||
student_survey_items
|
||||
end
|
||||
|
||||
def teacher_scales
|
||||
|
|
@ -61,31 +63,14 @@ class Measure < ActiveRecord::Base
|
|||
|
||||
def score(school:, academic_year:)
|
||||
@score ||= Hash.new do |memo, (school, academic_year)|
|
||||
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:)
|
||||
lacks_sufficient_survey_data = !meets_student_threshold && !meets_teacher_threshold
|
||||
incalculable_score = lacks_sufficient_survey_data && !includes_admin_data_items?
|
||||
|
||||
next Score.new(nil, false, false, false) if incalculable_score
|
||||
|
||||
scores = []
|
||||
if meets_teacher_threshold
|
||||
scores << collect_survey_item_average(survey_items: teacher_survey_items, school:,
|
||||
academic_year:)
|
||||
end
|
||||
if meets_student_threshold
|
||||
scores << collect_survey_item_average(survey_items: student_survey_items_by_survey_type(school:, academic_year:), school:,
|
||||
academic_year:)
|
||||
end
|
||||
scores << collect_admin_scale_average(admin_data_items:, school:, academic_year:) if includes_admin_data_items?
|
||||
next Score::NIL_SCORE if incalculable_score(school:, academic_year:)
|
||||
|
||||
scores = collect_averages_for_teacher_student_and_admin_data(school:, academic_year:)
|
||||
average = scores.flatten.compact.remove_blanks.average
|
||||
|
||||
next Score.new(nil, false, false, false) if average.nan?
|
||||
next Score::NIL_SCORE if average.nan?
|
||||
|
||||
memo[[school, academic_year]] =
|
||||
Score.new(average, meets_teacher_threshold, meets_student_threshold, meets_admin_data_threshold)
|
||||
memo[[school, academic_year]] = scorify(average:, school:, academic_year:)
|
||||
end
|
||||
|
||||
@score[[school, academic_year]]
|
||||
|
|
@ -94,10 +79,7 @@ class Measure < ActiveRecord::Base
|
|||
def student_score(school:, academic_year:)
|
||||
@student_score ||= Hash.new do |memo, (school, academic_year)|
|
||||
meets_student_threshold = sufficient_student_data?(school:, academic_year:)
|
||||
if meets_student_threshold
|
||||
average = collect_survey_item_average(survey_items: student_survey_items_by_survey_type(school:, academic_year:), school:,
|
||||
academic_year:)
|
||||
end
|
||||
average = student_average(school:, academic_year:) if meets_student_threshold
|
||||
memo[[school, academic_year]] = scorify(average:, school:, academic_year:)
|
||||
end
|
||||
|
||||
|
|
@ -107,10 +89,7 @@ class Measure < ActiveRecord::Base
|
|||
def teacher_score(school:, academic_year:)
|
||||
@teacher_score ||= Hash.new do |memo, (school, academic_year)|
|
||||
meets_teacher_threshold = sufficient_teacher_data?(school:, academic_year:)
|
||||
if meets_teacher_threshold
|
||||
average = collect_survey_item_average(survey_items: teacher_survey_items, school:,
|
||||
academic_year:)
|
||||
end
|
||||
average = teacher_average(school:, academic_year:) if meets_teacher_threshold
|
||||
memo[[school, academic_year]] = scorify(average:, school:, academic_year:)
|
||||
end
|
||||
|
||||
|
|
@ -141,12 +120,11 @@ class Measure < ActiveRecord::Base
|
|||
|
||||
def any_admin_data_collected?(school:, academic_year:)
|
||||
@any_admin_data_collected ||= Hash.new do |memo, (school, academic_year)|
|
||||
total_collected_admin_data_items = scales.map do |scale|
|
||||
scale.admin_data_items.map do |admin_data_item|
|
||||
total_collected_admin_data_items =
|
||||
admin_data_items.map do |admin_data_item|
|
||||
admin_data_item.admin_data_values.where(school:, academic_year:).count
|
||||
end
|
||||
end.flatten.sum
|
||||
memo[[school, academic_year]] = total_collected_admin_data_items > 0
|
||||
end.flatten.sum
|
||||
memo[[school, academic_year]] = total_collected_admin_data_items.positive?
|
||||
end
|
||||
@any_admin_data_collected[[school, academic_year]]
|
||||
end
|
||||
|
|
@ -178,9 +156,11 @@ class Measure < ActiveRecord::Base
|
|||
|
||||
def collect_admin_scale_average(admin_data_items:, school:, academic_year:)
|
||||
@collect_admin_scale_average ||= Hash.new do |memo, (admin_data_items, school, academic_year)|
|
||||
memo[[admin_data_items, school, academic_year]] = admin_data_items.map do |admin_data_item|
|
||||
admin_value = admin_data_item.admin_data_values.where(school:, academic_year:).first
|
||||
admin_value.likert_score if admin_value.present?
|
||||
memo[[admin_data_items, school, academic_year]] = begin
|
||||
admin_values = AdminDataValue.where(school:, academic_year:)
|
||||
admin_values.map do |admin_value|
|
||||
admin_value.likert_score if admin_value.present?
|
||||
end
|
||||
end
|
||||
end
|
||||
@collect_admin_scale_average[[admin_data_items, school, academic_year]]
|
||||
|
|
@ -204,19 +184,58 @@ class Measure < ActiveRecord::Base
|
|||
|
||||
def sufficient_student_data?(school:, academic_year:)
|
||||
return @sufficient_student_data ||= false unless includes_student_survey_items?
|
||||
return @sufficient_student_data ||= false if student_survey_items_by_survey_type(school:, academic_year:).all? do |survey_item|
|
||||
survey_item.survey_item_responses.where(school:, academic_year:).none?
|
||||
end
|
||||
return @sufficient_student_data ||= false if no_student_responses_exist?(school:, academic_year:)
|
||||
|
||||
@sufficient_student_data ||= subcategory.response_rate(school:, academic_year:).meets_student_threshold?
|
||||
end
|
||||
|
||||
def sufficient_teacher_data?(school:, academic_year:)
|
||||
return @sufficient_teacher_data ||= false unless includes_teacher_survey_items?
|
||||
return @sufficient_teacher_data ||= false if teacher_survey_items.all? do |survey_item|
|
||||
survey_item.survey_item_responses.where(school:, academic_year:).none?
|
||||
end
|
||||
return @sufficient_teacher_data ||= false if no_teacher_responses_exist?(school:, academic_year:)
|
||||
|
||||
@sufficient_teacher_data ||= subcategory.response_rate(school:, academic_year:).meets_teacher_threshold?
|
||||
end
|
||||
|
||||
def no_student_responses_exist?(school:, academic_year:)
|
||||
student_survey_items_by_survey_type(school:,
|
||||
academic_year:).all? do |survey_item|
|
||||
survey_item.survey_item_responses.where(school:,
|
||||
academic_year:).none?
|
||||
end
|
||||
end
|
||||
|
||||
def no_teacher_responses_exist?(school:, academic_year:)
|
||||
teacher_survey_items.all? do |survey_item|
|
||||
survey_item.survey_item_responses.where(school:,
|
||||
academic_year:).none?
|
||||
end
|
||||
end
|
||||
|
||||
def incalculable_score(school:, academic_year:)
|
||||
meets_student_threshold = sufficient_student_data?(school:, academic_year:)
|
||||
meets_teacher_threshold = sufficient_teacher_data?(school:, academic_year:)
|
||||
lacks_sufficient_survey_data = !meets_student_threshold && !meets_teacher_threshold
|
||||
lacks_sufficient_survey_data && !includes_admin_data_items?
|
||||
end
|
||||
|
||||
def collect_averages_for_teacher_student_and_admin_data(school:, academic_year:)
|
||||
scores = []
|
||||
scores << teacher_average(school:, academic_year:) if sufficient_teacher_data?(school:, academic_year:)
|
||||
scores << student_average(school:, academic_year:) if sufficient_student_data?(school:, academic_year:)
|
||||
scores << admin_data_averages(school:, academic_year:) if includes_admin_data_items?
|
||||
scores
|
||||
end
|
||||
|
||||
def teacher_average(school:, academic_year:)
|
||||
collect_survey_item_average(survey_items: teacher_survey_items, school:, academic_year:)
|
||||
end
|
||||
|
||||
def student_average(school:, academic_year:)
|
||||
collect_survey_item_average(survey_items: student_survey_items_by_survey_type(school:, academic_year:), school:,
|
||||
academic_year:)
|
||||
end
|
||||
|
||||
def admin_data_averages(school:, academic_year:)
|
||||
collect_admin_scale_average(admin_data_items:, school:, academic_year:)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
class Score < Struct.new(:average, :meets_teacher_threshold?, :meets_student_threshold?, :meets_admin_data_threshold?)
|
||||
NIL_SCORE = Score.new(nil, false, false, false)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class Subcategory < ActiveRecord::Base
|
|||
end
|
||||
|
||||
if @response_rate[[school, academic_year]].nil?
|
||||
@response_rate[[school, academic_year]] = create_response_rate(subcategory: self, school:, academic_year:)
|
||||
@response_rate[[school, academic_year]] = create_response_rate(school:, academic_year:)
|
||||
end
|
||||
|
||||
@response_rate[[school, academic_year]]
|
||||
|
|
@ -25,10 +25,11 @@ class Subcategory < ActiveRecord::Base
|
|||
|
||||
private
|
||||
|
||||
def create_response_rate(subcategory:, school:, academic_year:)
|
||||
def create_response_rate(school:, academic_year:)
|
||||
student = StudentResponseRateCalculator.new(subcategory: self, school:, academic_year:)
|
||||
teacher = TeacherResponseRateCalculator.new(subcategory: self, school:, academic_year:)
|
||||
ResponseRate.create(school:, academic_year:, subcategory: self, student_response_rate: student.rate, teacher_response_rate: teacher.rate,
|
||||
meets_student_threshold: student.meets_student_threshold?, meets_teacher_threshold: teacher.meets_teacher_threshold?)
|
||||
ResponseRate.create(school:, academic_year:, subcategory: self, student_response_rate: student.rate,
|
||||
teacher_response_rate: teacher.rate, meets_student_threshold: student.meets_student_threshold?,
|
||||
meets_teacher_threshold: teacher.meets_teacher_threshold?)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class AnalyzeBarPresenter
|
|||
else
|
||||
0.0
|
||||
end
|
||||
bar_height < MINIMUM_BAR_HEIGHT ? MINIMUM_BAR_HEIGHT : bar_height
|
||||
enforce_minimum_height(bar_height:)
|
||||
end
|
||||
|
||||
def percentage
|
||||
|
|
@ -63,4 +63,10 @@ class AnalyzeBarPresenter
|
|||
|
||||
score.average.round(6)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def enforce_minimum_height(bar_height:)
|
||||
bar_height < MINIMUM_BAR_HEIGHT ? MINIMUM_BAR_HEIGHT : bar_height
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,11 +4,7 @@ class SurveyResponsesDataLoader
|
|||
def self.load_data(filepath:)
|
||||
File.open(filepath) do |file|
|
||||
headers = file.first
|
||||
|
||||
survey_item_ids = CSV.parse(headers, headers: true).headers
|
||||
.filter { |header| header.present? }
|
||||
.filter { |header| header.start_with? 't-' or header.start_with? 's-' }
|
||||
survey_items = SurveyItem.where(survey_item_id: survey_item_ids)
|
||||
survey_items = SurveyItem.where(survey_item_id: get_survey_item_ids_from_headers(file:, headers:))
|
||||
|
||||
file.lazy.each_slice(1000) do |lines|
|
||||
survey_item_responses = CSV.parse(lines.join, headers:).map do |row|
|
||||
|
|
@ -23,17 +19,16 @@ class SurveyResponsesDataLoader
|
|||
private
|
||||
|
||||
def self.process_row(row:, survey_items:)
|
||||
response_date = Date.parse(row['Recorded Date'] || row['RecordedDate'])
|
||||
academic_year = AcademicYear.find_by_date response_date
|
||||
return unless dese_id?(row['DESE ID'])
|
||||
|
||||
school = School.find_by_dese_id(row['DESE ID'])
|
||||
return unless school.present?
|
||||
|
||||
process_survey_items(row:, survey_items:, school:)
|
||||
end
|
||||
|
||||
def self.process_survey_items(row:, survey_items:, school:)
|
||||
response_id = row['Response ID'] || row['ResponseId'] || row['ResponseID']
|
||||
|
||||
dese_id = row['DESE ID']
|
||||
return if dese_id.nil?
|
||||
|
||||
school = School.find_by_dese_id(dese_id)
|
||||
return if school.nil?
|
||||
|
||||
survey_items.map do |survey_item|
|
||||
likert_score = row[survey_item.survey_item_id]
|
||||
next if likert_score.nil?
|
||||
|
|
@ -44,22 +39,42 @@ class SurveyResponsesDataLoader
|
|||
end
|
||||
|
||||
survey_item_response = SurveyItemResponse.where(response_id:, survey_item:).first
|
||||
if survey_item_response.present?
|
||||
survey_item_response.update!(likert_score:) if survey_item_response.likert_score != likert_score
|
||||
next
|
||||
else
|
||||
SurveyItemResponse.new(
|
||||
response_id:,
|
||||
academic_year:,
|
||||
school:,
|
||||
survey_item:,
|
||||
likert_score:
|
||||
)
|
||||
end
|
||||
create_or_update_survey_item_response(survey_item_response:, likert_score:, school:, response_id:, row:,
|
||||
survey_item:)
|
||||
end.compact
|
||||
end
|
||||
|
||||
def self.create_or_update_survey_item_response(survey_item_response:, likert_score:, school:, row:, survey_item:, response_id:)
|
||||
if survey_item_response.present?
|
||||
survey_item_response.update!(likert_score:) if survey_item_response.likert_score != likert_score
|
||||
[]
|
||||
else
|
||||
SurveyItemResponse.new(response_id:, academic_year: academic_year(row), school:, survey_item:, likert_score:)
|
||||
end
|
||||
end
|
||||
|
||||
def self.get_survey_item_ids_from_headers(file:, headers:)
|
||||
CSV.parse(headers, headers: true).headers
|
||||
.filter { |header| header.present? }
|
||||
.filter { |header| header.start_with? 't-' or header.start_with? 's-' }
|
||||
end
|
||||
|
||||
def self.dese_id?(dese_id)
|
||||
dese_id.present?
|
||||
end
|
||||
|
||||
def self.response_date(row)
|
||||
Date.parse(row['Recorded Date'] || row['RecordedDate'])
|
||||
end
|
||||
|
||||
def self.academic_year(row)
|
||||
AcademicYear.find_by_date response_date(row)
|
||||
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?
|
||||
end
|
||||
|
||||
module StringMonkeyPatches
|
||||
|
|
|
|||
1204
lib/tasks/data.rake
1204
lib/tasks/data.rake
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue