Compute the score for a given construct, school, and academic year

pull/1/head
Alex Basson 4 years ago
parent 9007cd3078
commit 1782ef3482

@ -1,45 +1,30 @@
class DashboardController < ApplicationController
before_action :set_school
def index
authenticate(district.name.downcase, "#{district.name.downcase}!")
@construct_graph_row_presenters = [
ConstructGraphRowPresenter.new(construct: Construct.find_by_construct_id('1A-i'), score: score('1A-i'))
]
@construct_graph_row_presenters = Construct.where(construct_id: '1A-i').map do | construct |
ConstructGraphRowPresenter.new(
construct: construct,
score: SurveyResponseAggregator.score(school: school, academic_year: academic_year, construct: construct)
)
end
end
private
def set_school
@school = School.find_by_slug school_slug
def school
@school ||= School.find_by_slug school_slug
end
def school_slug
params[:school_id]
def district
@district ||= school.district
end
def district
@district ||= @school.district
def school_slug
params[:school_id]
end
def score(construct_id)
# for this school, get the score for this construct
# what we mean by this is:
# for the given school, find the responses to the survey of the given academic year (AY)
# that respond to questions that belong the given construct,
# then average the scores for those responses
# E.g. Find the responses from AY2020-21 from Milford High School, then get just those
# responses that correspond to questions from Professional Qualifications
# and then average the scores from those responses
# all_responses_from_milford_in_2020-21 = SurveyResponse.where('academic_year = 2020-21').where('school = Milford High School')
# milford-2020-21-responses-to-1A-i = all_responses_from_milford_2020-21.filter { |response| response.question.construct.construct_id = '1A-i' }
# score = average(milford-2020-21-responses-to-1A-i)
4.8
def academic_year
params[:year]
end
end
#
# response belongs_to question
# question belongs_to construct
# response.question.construct

@ -1,3 +0,0 @@
class Item < ActiveRecord::Base
belongs_to :construct
end

@ -0,0 +1,3 @@
class SurveyItem < ActiveRecord::Base
belongs_to :construct
end

@ -0,0 +1,4 @@
class SurveyResponse < ActiveRecord::Base
belongs_to :school
belongs_to :survey_item
end

@ -0,0 +1,16 @@
class Array
def average
self.sum.to_f / self.size
end
end
class SurveyResponseAggregator
def self.score(academic_year:, school:, construct:)
SurveyResponse
.where(academic_year: academic_year)
.where(school: school)
.filter { |survey_response| survey_response.survey_item.construct == construct }
.map { |survey_response| survey_response.likert_score }
.average
end
end

@ -1,10 +0,0 @@
class CreateItems < ActiveRecord::Migration[5.0]
def change
create_table :items do |t|
t.integer :construct_id
t.string :prompt
end
add_foreign_key :items, :constructs
end
end

@ -0,0 +1,10 @@
class CreateSurveyItems < ActiveRecord::Migration[5.0]
def change
create_table :survey_items do |t|
t.integer :construct_id
t.string :prompt
end
add_foreign_key :survey_items, :constructs
end
end

@ -0,0 +1,13 @@
class CreateSurveyResponses < ActiveRecord::Migration[5.0]
def change
create_table :survey_responses do |t|
t.string :academic_year
t.integer :likert_score
t.integer :school_id
t.integer :survey_item_id
end
add_foreign_key :survey_responses, :schools
add_foreign_key :survey_responses, :survey_items
end
end

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20210915183344) do
ActiveRecord::Schema.define(version: 20210916143538) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -64,11 +64,6 @@ ActiveRecord::Schema.define(version: 20210915183344) do
t.datetime "updated_at", null: false
end
create_table "items", force: :cascade do |t|
t.integer "construct_id"
t.string "prompt"
end
create_table "question_lists", force: :cascade do |t|
t.string "name"
t.text "description"
@ -208,6 +203,18 @@ ActiveRecord::Schema.define(version: 20210915183344) do
t.datetime "updated_at", null: false
end
create_table "survey_items", force: :cascade do |t|
t.integer "construct_id"
t.string "prompt"
end
create_table "survey_responses", force: :cascade do |t|
t.string "academic_year"
t.integer "likert_score"
t.integer "school_id"
t.integer "survey_item_id"
end
create_table "user_schools", force: :cascade do |t|
t.integer "user_id"
t.integer "school_id"
@ -233,9 +240,11 @@ ActiveRecord::Schema.define(version: 20210915183344) do
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
end
add_foreign_key "items", "constructs"
add_foreign_key "recipient_lists", "schools"
add_foreign_key "schedules", "schools"
add_foreign_key "school_categories", "categories"
add_foreign_key "school_categories", "schools"
add_foreign_key "survey_items", "constructs"
add_foreign_key "survey_responses", "schools"
add_foreign_key "survey_responses", "survey_items"
end

@ -1,6 +1,6 @@
require 'csv'
Item.destroy_all
SurveyItem.destroy_all
Construct.destroy_all
csv_file = File.read(Rails.root.join('data', 'AY2020-21_construct_items.csv'))
@ -18,7 +18,7 @@ CSV.parse(csv_file, headers: true).each do |row|
end
item_prompt = row['Survey Item']
Item.create construct: Construct.find_by_construct_id(construct_id), prompt: item_prompt
SurveyItem.create construct: Construct.find_by_construct_id(construct_id), prompt: item_prompt
end
end

@ -2,12 +2,22 @@ require "rails_helper"
feature "School dashboard", type: feature do
let(:district) { District.create name: 'Winchester' }
let(:school) {
School.create name: 'Winchester High School', slug: 'winchester-high-school', district: district
}
let(:school) { School.create name: 'Winchester High School', slug: 'winchester-high-school', district: district }
let(:construct) { Construct.find_by_construct_id('1A-i') }
let(:survey_item_1_for_construct) { SurveyItem.create construct: construct }
let(:survey_item_2_for_construct) { SurveyItem.create construct: construct }
let(:construct_row_bars) { page.all('rect.construct-row-bar') }
let(:ay_2020_21) { '2020-21' }
before :each do
SurveyResponse.create academic_year: ay_2020_21, school: school, survey_item: survey_item_1_for_construct, likert_score: 4
SurveyResponse.create academic_year: ay_2020_21, school: school, survey_item: survey_item_2_for_construct, likert_score: 5
end
scenario "User authentication fails" do
page.driver.browser.basic_authorize('wrong username', 'wrong password')
@ -19,12 +29,12 @@ feature "School dashboard", type: feature do
scenario "User views a school dashboard" do
page.driver.browser.basic_authorize(username, password)
visit "/districts/winchester/schools/#{school.slug}/dashboard?year=2020-21"
visit "/districts/winchester/schools/#{school.slug}/dashboard?year=#{ay_2020_21}"
expect(page).to have_text(school.name)
expect(page).to have_text('Professional Qualifications')
first_row_bar = construct_row_bars.first
expect(first_row_bar['width']).to eq '283'
expect(first_row_bar['width']).to eq '179'
end
let(:username) { 'winchester' }

@ -1,7 +0,0 @@
require 'rails_helper'
describe Item, type: :model do
it('has all the questions') do
expect(Item.count).to eq 153
end
end

@ -0,0 +1,7 @@
require 'rails_helper'
describe SurveyItem, type: :model do
it('has all the questions') do
expect(SurveyItem.count).to eq 153
end
end

@ -0,0 +1,60 @@
require 'rails_helper'
describe SurveyResponseAggregator, type: :model do
let(:ay_2020_21) { '2020-21' }
let(:ay_2021_22) { '2021-22' }
let(:school_a) { School.create name: 'School A' }
let(:school_b) { School.create name: 'School A' }
let(:construct_a) { Construct.create name: 'Construct A', construct_id: 'construct-a-id' }
let(:construct_b) { Construct.create name: 'Construct B', construct_id: 'construct-b-id' }
let(:survey_item_1_for_construct_a) { SurveyItem.create construct: construct_a }
let(:survey_item_2_for_construct_a) { SurveyItem.create construct: construct_a }
let(:survey_item_1_for_construct_b) { SurveyItem.create construct: construct_b }
let(:survey_item_2_for_construct_b) { SurveyItem.create construct: construct_b }
before :each do
SurveyResponse.create academic_year: ay_2020_21, school: school_a, survey_item: survey_item_1_for_construct_a, likert_score: 1
SurveyResponse.create academic_year: ay_2020_21, school: school_a, survey_item: survey_item_2_for_construct_a, likert_score: 2
SurveyResponse.create academic_year: ay_2020_21, school: school_a, survey_item: survey_item_1_for_construct_b, likert_score: 1
SurveyResponse.create academic_year: ay_2020_21, school: school_a, survey_item: survey_item_2_for_construct_b, likert_score: 3
SurveyResponse.create academic_year: ay_2020_21, school: school_b, survey_item: survey_item_1_for_construct_a, likert_score: 1
SurveyResponse.create academic_year: ay_2020_21, school: school_b, survey_item: survey_item_2_for_construct_a, likert_score: 4
SurveyResponse.create academic_year: ay_2020_21, school: school_b, survey_item: survey_item_1_for_construct_b, likert_score: 1
SurveyResponse.create academic_year: ay_2020_21, school: school_b, survey_item: survey_item_2_for_construct_b, likert_score: 5
SurveyResponse.create academic_year: ay_2021_22, school: school_a, survey_item: survey_item_1_for_construct_a, likert_score: 2
SurveyResponse.create academic_year: ay_2021_22, school: school_a, survey_item: survey_item_2_for_construct_a, likert_score: 3
SurveyResponse.create academic_year: ay_2021_22, school: school_a, survey_item: survey_item_1_for_construct_b, likert_score: 2
SurveyResponse.create academic_year: ay_2021_22, school: school_a, survey_item: survey_item_2_for_construct_b, likert_score: 4
SurveyResponse.create academic_year: ay_2021_22, school: school_b, survey_item: survey_item_1_for_construct_a, likert_score: 2
SurveyResponse.create academic_year: ay_2021_22, school: school_b, survey_item: survey_item_2_for_construct_a, likert_score: 5
SurveyResponse.create academic_year: ay_2021_22, school: school_b, survey_item: survey_item_1_for_construct_b, likert_score: 3
SurveyResponse.create academic_year: ay_2021_22, school: school_b, survey_item: survey_item_2_for_construct_b, likert_score: 5
end
describe '.score' do
it 'returns the average score of the survey responses for the given school, academic year, and construct' do
expect(SurveyResponseAggregator.score(academic_year: ay_2020_21, school: school_a, construct: construct_a)).to eq 1.5
expect(SurveyResponseAggregator.score(academic_year: ay_2020_21, school: school_a, construct: construct_b)).to eq 2.0
expect(SurveyResponseAggregator.score(academic_year: ay_2020_21, school: school_b, construct: construct_a)).to eq 2.5
expect(SurveyResponseAggregator.score(academic_year: ay_2020_21, school: school_b, construct: construct_b)).to eq 3.0
expect(SurveyResponseAggregator.score(academic_year: ay_2021_22, school: school_a, construct: construct_a)).to eq 2.5
expect(SurveyResponseAggregator.score(academic_year: ay_2021_22, school: school_a, construct: construct_b)).to eq 3.0
expect(SurveyResponseAggregator.score(academic_year: ay_2021_22, school: school_b, construct: construct_a)).to eq 3.5
expect(SurveyResponseAggregator.score(academic_year: ay_2021_22, school: school_b, construct: construct_b)).to eq 4.0
end
end
end
Loading…
Cancel
Save