Refactor based on rubocop and reek suggestions

pull/1/head
rebuilt 3 years ago
parent fc853c4fbc
commit 18b479b8b2

@ -1,15 +1,28 @@
class AnalyzeController < SqmApplicationController class AnalyzeController < SqmApplicationController
def index 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.find_by_category_id(params[:category])
@category ||= Category.order(:category_id).first @category ||= Category.order(:category_id).first
@categories = Category.all.order(:category_id) @categories = Category.all.order(:category_id)
end
def assign_subcategories
@subcategories = @category.subcategories.order(:subcategory_id) @subcategories = @category.subcategories.order(:subcategory_id)
@subcategory ||= Subcategory.find_by_subcategory_id(params[:subcategory]) @subcategory ||= Subcategory.find_by_subcategory_id(params[:subcategory])
@subcategory ||= @subcategories.first @subcategory ||= @subcategories.first
end
def assign_measures
@measures = @subcategory.measures.order(:measure_id).includes(%i[scales admin_data_items subcategory]) @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 @available_academic_years = AcademicYear.order(:range).all
@academic_year_params = params[:academic_years].split(',') if params[:academic_years] @academic_year_params = params[:academic_years].split(',') if params[:academic_years]
@selected_academic_years = [] @selected_academic_years = []

@ -1,3 +1,5 @@
# frozen_string_literal: true
class Measure < ActiveRecord::Base class Measure < ActiveRecord::Base
belongs_to :subcategory, counter_cache: true belongs_to :subcategory, counter_cache: true
has_one :category, through: :subcategory has_one :category, through: :subcategory
@ -24,9 +26,9 @@ class Measure < ActiveRecord::Base
def student_survey_items_by_survey_type(school:, academic_year:) def student_survey_items_by_survey_type(school:, academic_year:)
survey = Survey.where(school:, academic_year:).first 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 end
def teacher_scales def teacher_scales
@ -61,31 +63,14 @@ class Measure < ActiveRecord::Base
def score(school:, academic_year:) def score(school:, academic_year:)
@score ||= Hash.new do |memo, (school, academic_year)| @score ||= Hash.new do |memo, (school, academic_year)|
meets_student_threshold = sufficient_student_data?(school:, academic_year:) next Score::NIL_SCORE if incalculable_score(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?
scores = collect_averages_for_teacher_student_and_admin_data(school:, academic_year:)
average = scores.flatten.compact.remove_blanks.average 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]] = memo[[school, academic_year]] = scorify(average:, school:, academic_year:)
Score.new(average, meets_teacher_threshold, meets_student_threshold, meets_admin_data_threshold)
end end
@score[[school, academic_year]] @score[[school, academic_year]]
@ -94,10 +79,7 @@ class Measure < ActiveRecord::Base
def student_score(school:, academic_year:) def student_score(school:, academic_year:)
@student_score ||= Hash.new do |memo, (school, academic_year)| @student_score ||= Hash.new do |memo, (school, academic_year)|
meets_student_threshold = sufficient_student_data?(school:, academic_year:) meets_student_threshold = sufficient_student_data?(school:, academic_year:)
if meets_student_threshold average = student_average(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
memo[[school, academic_year]] = scorify(average:, school:, academic_year:) memo[[school, academic_year]] = scorify(average:, school:, academic_year:)
end end
@ -107,10 +89,7 @@ class Measure < ActiveRecord::Base
def teacher_score(school:, academic_year:) def teacher_score(school:, academic_year:)
@teacher_score ||= Hash.new do |memo, (school, academic_year)| @teacher_score ||= Hash.new do |memo, (school, academic_year)|
meets_teacher_threshold = sufficient_teacher_data?(school:, academic_year:) meets_teacher_threshold = sufficient_teacher_data?(school:, academic_year:)
if meets_teacher_threshold average = teacher_average(school:, academic_year:) if meets_teacher_threshold
average = collect_survey_item_average(survey_items: teacher_survey_items, school:,
academic_year:)
end
memo[[school, academic_year]] = scorify(average:, school:, academic_year:) memo[[school, academic_year]] = scorify(average:, school:, academic_year:)
end end
@ -141,12 +120,11 @@ class Measure < ActiveRecord::Base
def any_admin_data_collected?(school:, academic_year:) def any_admin_data_collected?(school:, academic_year:)
@any_admin_data_collected ||= Hash.new do |memo, (school, academic_year)| @any_admin_data_collected ||= Hash.new do |memo, (school, academic_year)|
total_collected_admin_data_items = scales.map do |scale| total_collected_admin_data_items =
scale.admin_data_items.map do |admin_data_item| admin_data_items.map do |admin_data_item|
admin_data_item.admin_data_values.where(school:, academic_year:).count admin_data_item.admin_data_values.where(school:, academic_year:).count
end end.flatten.sum
end.flatten.sum memo[[school, academic_year]] = total_collected_admin_data_items.positive?
memo[[school, academic_year]] = total_collected_admin_data_items > 0
end end
@any_admin_data_collected[[school, academic_year]] @any_admin_data_collected[[school, academic_year]]
end end
@ -178,9 +156,11 @@ class Measure < ActiveRecord::Base
def collect_admin_scale_average(admin_data_items:, school:, academic_year:) 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)| @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| memo[[admin_data_items, school, academic_year]] = begin
admin_value = admin_data_item.admin_data_values.where(school:, academic_year:).first admin_values = AdminDataValue.where(school:, academic_year:)
admin_value.likert_score if admin_value.present? admin_values.map do |admin_value|
admin_value.likert_score if admin_value.present?
end
end end
end end
@collect_admin_scale_average[[admin_data_items, school, academic_year]] @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:) def sufficient_student_data?(school:, academic_year:)
return @sufficient_student_data ||= false unless includes_student_survey_items? 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| return @sufficient_student_data ||= false if no_student_responses_exist?(school:, academic_year:)
survey_item.survey_item_responses.where(school:, academic_year:).none?
end
@sufficient_student_data ||= subcategory.response_rate(school:, academic_year:).meets_student_threshold? @sufficient_student_data ||= subcategory.response_rate(school:, academic_year:).meets_student_threshold?
end end
def sufficient_teacher_data?(school:, academic_year:) def sufficient_teacher_data?(school:, academic_year:)
return @sufficient_teacher_data ||= false unless includes_teacher_survey_items? return @sufficient_teacher_data ||= false unless includes_teacher_survey_items?
return @sufficient_teacher_data ||= false if teacher_survey_items.all? do |survey_item| return @sufficient_teacher_data ||= false if no_teacher_responses_exist?(school:, academic_year:)
survey_item.survey_item_responses.where(school:, academic_year:).none?
end
@sufficient_teacher_data ||= subcategory.response_rate(school:, academic_year:).meets_teacher_threshold? @sufficient_teacher_data ||= subcategory.response_rate(school:, academic_year:).meets_teacher_threshold?
end 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 end

@ -1,2 +1,3 @@
class Score < Struct.new(:average, :meets_teacher_threshold?, :meets_student_threshold?, :meets_admin_data_threshold?) class Score < Struct.new(:average, :meets_teacher_threshold?, :meets_student_threshold?, :meets_admin_data_threshold?)
NIL_SCORE = Score.new(nil, false, false, false)
end end

@ -17,7 +17,7 @@ class Subcategory < ActiveRecord::Base
end end
if @response_rate[[school, academic_year]].nil? 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 end
@response_rate[[school, academic_year]] @response_rate[[school, academic_year]]
@ -25,10 +25,11 @@ class Subcategory < ActiveRecord::Base
private private
def create_response_rate(subcategory:, school:, academic_year:) def create_response_rate(school:, academic_year:)
student = StudentResponseRateCalculator.new(subcategory: self, school:, academic_year:) student = StudentResponseRateCalculator.new(subcategory: self, school:, academic_year:)
teacher = TeacherResponseRateCalculator.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, ResponseRate.create(school:, academic_year:, subcategory: self, student_response_rate: student.rate,
meets_student_threshold: student.meets_student_threshold?, meets_teacher_threshold: teacher.meets_teacher_threshold?) teacher_response_rate: teacher.rate, meets_student_threshold: student.meets_student_threshold?,
meets_teacher_threshold: teacher.meets_teacher_threshold?)
end end
end end

@ -41,7 +41,7 @@ class AnalyzeBarPresenter
else else
0.0 0.0
end end
bar_height < MINIMUM_BAR_HEIGHT ? MINIMUM_BAR_HEIGHT : bar_height enforce_minimum_height(bar_height:)
end end
def percentage def percentage
@ -63,4 +63,10 @@ class AnalyzeBarPresenter
score.average.round(6) score.average.round(6)
end end
private
def enforce_minimum_height(bar_height:)
bar_height < MINIMUM_BAR_HEIGHT ? MINIMUM_BAR_HEIGHT : bar_height
end
end end

@ -4,11 +4,7 @@ class SurveyResponsesDataLoader
def self.load_data(filepath:) def self.load_data(filepath:)
File.open(filepath) do |file| File.open(filepath) do |file|
headers = file.first headers = file.first
survey_items = SurveyItem.where(survey_item_id: get_survey_item_ids_from_headers(file:, headers:))
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)
file.lazy.each_slice(1000) do |lines| file.lazy.each_slice(1000) do |lines|
survey_item_responses = CSV.parse(lines.join, headers:).map do |row| survey_item_responses = CSV.parse(lines.join, headers:).map do |row|
@ -23,17 +19,16 @@ class SurveyResponsesDataLoader
private private
def self.process_row(row:, survey_items:) def self.process_row(row:, survey_items:)
response_date = Date.parse(row['Recorded Date'] || row['RecordedDate']) return unless dese_id?(row['DESE ID'])
academic_year = AcademicYear.find_by_date response_date
response_id = row['Response ID'] || row['ResponseId'] || row['ResponseID']
dese_id = row['DESE ID'] school = School.find_by_dese_id(row['DESE ID'])
return if dese_id.nil? return unless school.present?
school = School.find_by_dese_id(dese_id) process_survey_items(row:, survey_items:, school:)
return if school.nil? end
def self.process_survey_items(row:, survey_items:, school:)
response_id = row['Response ID'] || row['ResponseId'] || row['ResponseID']
survey_items.map do |survey_item| survey_items.map do |survey_item|
likert_score = row[survey_item.survey_item_id] likert_score = row[survey_item.survey_item_id]
next if likert_score.nil? next if likert_score.nil?
@ -44,22 +39,42 @@ class SurveyResponsesDataLoader
end end
survey_item_response = SurveyItemResponse.where(response_id:, survey_item:).first survey_item_response = SurveyItemResponse.where(response_id:, survey_item:).first
if survey_item_response.present? create_or_update_survey_item_response(survey_item_response:, likert_score:, school:, response_id:, row:,
survey_item_response.update!(likert_score:) if survey_item_response.likert_score != likert_score survey_item:)
next
else
SurveyItemResponse.new(
response_id:,
academic_year:,
school:,
survey_item:,
likert_score:
)
end
end.compact end.compact
end 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_row
private_class_method :process_survey_items
private_class_method :get_survey_item_ids_from_headers
private_class_method :dese_id?
end end
module StringMonkeyPatches module StringMonkeyPatches

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save