diff --git a/app/models/response_rate.rb b/app/models/response_rate.rb new file mode 100644 index 00000000..20f39759 --- /dev/null +++ b/app/models/response_rate.rb @@ -0,0 +1,88 @@ +class ResponseRate + def initialize(subcategory:, school:, academic_year:) + @subcategory = subcategory + @school = school + @academic_year = academic_year + end + + def student + @student_response_rate ||= begin + return 0 unless student_survey_item_count.positive? + + average_responses_per_survey_item = student_response_count / student_survey_item_count + + return 0 unless total_possible_student_responses.positive? + + (average_responses_per_survey_item / total_possible_student_responses * 100).round + end + end + + def teacher + @teacher_response_rate ||= begin + return 0 unless teacher_survey_item_count.positive? + + average_responses_per_survey_item = teacher_response_count / teacher_survey_item_count + + return 0 unless total_possible_teacher_responses.positive? + + (average_responses_per_survey_item / total_possible_teacher_responses * 100).round + end + end + + private + + def total_possible_student_responses + @total_possible_student_responses ||= total_possible_responses do |responses| + responses.total_students + end + end + + def total_possible_teacher_responses + @total_possible_teacher_responses ||= total_possible_responses do |responses| + responses.total_teachers + end + end + + def total_possible_responses + total_responses = Respondent.where(school: @school, academic_year: @academic_year).first + return 0 unless total_responses.present? + + yield total_responses + end + + def student_response_count + @student_response_count ||= response_count do |measure| + next 0 unless measure.includes_student_survey_items? + + SurveyItemResponse.student_responses_for_measure(measure, @school, @academic_year).count + end + end + + def teacher_response_count + @teacher_response_count ||= response_count do |measure| + next 0 unless measure.includes_teacher_survey_items? + + SurveyItemResponse.teacher_responses_for_measure(measure, @school, @academic_year).count + end + end + + def response_count(&block) + @subcategory.measures.map(&block).sum + end + + def student_survey_item_count + @student_survey_item_count ||= survey_item_count do |measure| + measure.student_survey_items.count + end + end + + def teacher_survey_item_count + @teacher_survey_item_count ||= survey_item_count do |measure| + measure.teacher_survey_items.count + end + end + + def survey_item_count(&block) + @subcategory.measures.map(&block).sum + end +end diff --git a/app/models/survey_item_response.rb b/app/models/survey_item_response.rb index 76f663b7..838bc481 100644 --- a/app/models/survey_item_response.rb +++ b/app/models/survey_item_response.rb @@ -16,21 +16,6 @@ class SurveyItemResponse < ActiveRecord::Base end.average end - def self.average_number_of_student_respondents(subcategory:, school:, academic_year:) - response_count = subcategory.measures.map do |measure| - next 0 unless measure.includes_student_survey_items? - - SurveyItemResponse.student_responses_for_measure(measure, school, academic_year).count - end.sum - - survey_item_count = subcategory.measures.map do |measure| - measure.student_survey_items.count - end.sum - return 0 unless survey_item_count.positive? - - response_count / survey_item_count - end - def self.measures_with_sufficient_data(subcategory:, school:, academic_year:) subcategory.measures.select do |measure| sufficient_data?(measure: measure, school: school, academic_year: academic_year) diff --git a/app/presenters/subcategory_presenter.rb b/app/presenters/subcategory_presenter.rb index 721bee0b..f060312d 100644 --- a/app/presenters/subcategory_presenter.rb +++ b/app/presenters/subcategory_presenter.rb @@ -3,6 +3,7 @@ class SubcategoryPresenter @subcategory = subcategory @academic_year = academic_year @school = school + @response_rate = ResponseRate.new(subcategory: @subcategory, school: @school, academic_year: @academic_year) end def id @@ -31,10 +32,11 @@ class SubcategoryPresenter end def student_response_rate - @student_response_rate ||= response_rate(type: :total_students) do - SurveyItemResponse.average_number_of_student_respondents(subcategory: @subcategory, school: @school, - academic_year: @academic_year) - end + @response_rate.student + end + + def teacher_response_rate + @response_rate.teacher end def measure_presenters @@ -57,16 +59,4 @@ class SubcategoryPresenter def measures @measures ||= @subcategory.measures.includes([:admin_data_items]).order(:measure_id) end - - def response_rate(type:) - number_of_responses = yield - total_responses = Respondent.where(school: @school, academic_year: @academic_year).first - return 0 unless total_responses.present? - - total_possible_responses = total_responses.send(type) - - return 0 if number_of_responses.nil? || total_possible_responses == 0 - - (number_of_responses / total_possible_responses * 100).round - end end diff --git a/app/views/categories/_subcategory_section.html.erb b/app/views/categories/_subcategory_section.html.erb index 797af55e..06708d08 100644 --- a/app/views/categories/_subcategory_section.html.erb +++ b/app/views/categories/_subcategory_section.html.erb @@ -15,13 +15,10 @@

<%= subcategory.student_response_rate %>%

of students responded

- <%#
%> - <%#

<%= subcategory.teacher_response_rate %1>%

%> - <%#

of teachers responded

%> - <%#

%> - <%# <%= subcategory.total_teachers %1> %> - <%#

%> - +
+

<%= subcategory.teacher_response_rate %>%

+

of teachers responded

+
diff --git a/spec/models/response_rate_spec.rb b/spec/models/response_rate_spec.rb new file mode 100644 index 00000000..f703cae1 --- /dev/null +++ b/spec/models/response_rate_spec.rb @@ -0,0 +1,76 @@ +require 'rails_helper' + +describe ResponseRate, type: :model do + let(:school) { create(:school) } + let(:ay) { create(:academic_year) } + let(:survey_respondents) do + create(:respondent, school: school, total_students: SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, + total_teachers: SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD, academic_year: ay) + end + + describe '.student' do + let(:subcategory) { create(:subcategory) } + let(:sufficient_measure_1) { create(:measure, subcategory: subcategory) } + let(:sufficient_measure_2) { create(:measure, subcategory: subcategory) } + let(:insufficient_measure) { create(:measure, subcategory: subcategory) } + let(:sufficient_teacher_survey_item) { create(:teacher_survey_item, measure: sufficient_measure_1) } + let(:sufficient_student_survey_item_1) { create(:student_survey_item, measure: sufficient_measure_1) } + let(:insufficient_teacher_survey_item) { create(:teacher_survey_item, measure: insufficient_measure) } + let(:sufficient_student_survey_item_2) { create(:student_survey_item, measure: sufficient_measure_2) } + let(:insufficient_student_survey_item) { create(:student_survey_item, measure: insufficient_measure) } + + before :each do + survey_respondents + create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD, survey_item: sufficient_teacher_survey_item, + academic_year: ay, school: school, likert_score: 1) + create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, survey_item: sufficient_student_survey_item_1, + academic_year: ay, school: school, likert_score: 4) + create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD + 1, survey_item: sufficient_student_survey_item_2, + academic_year: ay, school: school, likert_score: 4) + create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD - 1, + survey_item: insufficient_teacher_survey_item, academic_year: ay, school: school, likert_score: 1) + create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD - 1, + survey_item: insufficient_student_survey_item, academic_year: ay, school: school, likert_score: 1) + end + + context 'when the average number of student responses per question in a subcategory is equal to the student response threshold' do + it 'returns 100 percent' do + expect(ResponseRate.new(subcategory: subcategory, school: school, + academic_year: ay).student).to eq 100 + end + end + end + + describe '.teacher' do + let(:subcategory) { create(:subcategory) } + let(:sufficient_measure_1) { create(:measure, subcategory: subcategory) } + let(:sufficient_measure_2) { create(:measure, subcategory: subcategory) } + let(:insufficient_measure) { create(:measure, subcategory: subcategory) } + let(:sufficient_teacher_survey_item_1) { create(:teacher_survey_item, measure: sufficient_measure_1) } + let(:sufficient_teacher_survey_item_2) { create(:teacher_survey_item, measure: sufficient_measure_1) } + let(:sufficient_student_survey_item_1) { create(:student_survey_item, measure: sufficient_measure_1) } + let(:insufficient_teacher_survey_item) { create(:teacher_survey_item, measure: insufficient_measure) } + let(:insufficient_student_survey_item) { create(:student_survey_item, measure: insufficient_measure) } + + before :each do + survey_respondents + create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD, survey_item: sufficient_teacher_survey_item_1, + academic_year: ay, school: school, likert_score: 1) + create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD + 1, survey_item: sufficient_teacher_survey_item_2, + academic_year: ay, school: school, likert_score: 1) + create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, survey_item: sufficient_student_survey_item_1, + academic_year: ay, school: school, likert_score: 4) + create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD - 1, + survey_item: insufficient_teacher_survey_item, academic_year: ay, school: school, likert_score: 1) + create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD - 1, + survey_item: insufficient_student_survey_item, academic_year: ay, school: school, likert_score: 1) + end + + context 'when the average number of student responses per question in a subcategory is equal to the student response threshold' do + it 'returns 100 percent' do + expect(ResponseRate.new(subcategory: subcategory, school: school, + academic_year: ay).teacher).to eq 100 + end + end + end +end diff --git a/spec/models/survey_item_response_spec.rb b/spec/models/survey_item_response_spec.rb index d956f1ff..1e68125a 100644 --- a/spec/models/survey_item_response_spec.rb +++ b/spec/models/survey_item_response_spec.rb @@ -334,33 +334,4 @@ describe SurveyItemResponse, type: :model do expect(SurveyItemResponse.responses_for_measure(measure: insufficient_measure, school: school, academic_year: ay)).to be nil end end - - describe '.average_number_of_student_respondents' do - let(:subcategory) { create(:subcategory) } - let(:sufficient_measure_1) { create(:measure, subcategory: subcategory) } - let(:sufficient_measure_2) { create(:measure, subcategory: subcategory) } - let(:insufficient_measure) { create(:measure, subcategory: subcategory) } - let(:sufficient_teacher_survey_item) { create(:teacher_survey_item, measure: sufficient_measure_1) } - let(:sufficient_student_survey_item_1) { create(:student_survey_item, measure: sufficient_measure_1) } - let(:insufficient_teacher_survey_item) { create(:teacher_survey_item, measure: insufficient_measure) } - let(:sufficient_student_survey_item_2) { create(:student_survey_item, measure: sufficient_measure_2) } - let(:insufficient_student_survey_item) { create(:student_survey_item, measure: insufficient_measure) } - - before :each do - create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD, survey_item: sufficient_teacher_survey_item, - academic_year: ay, school: school, likert_score: 1) - create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD, survey_item: sufficient_student_survey_item_1, - academic_year: ay, school: school, likert_score: 4) - create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD + 1, survey_item: sufficient_student_survey_item_2, - academic_year: ay, school: school, likert_score: 4) - create_list(:survey_item_response, SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD - 1, - survey_item: insufficient_teacher_survey_item, academic_year: ay, school: school, likert_score: 1) - create_list(:survey_item_response, SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD - 1, - survey_item: insufficient_student_survey_item, academic_year: ay, school: school, likert_score: 1) - end - - it 'returns only responses in a measure that meets the low threshold' do - expect(SurveyItemResponse.average_number_of_student_respondents(subcategory: subcategory, school: school, academic_year: ay)).to eq SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD - end - end end