mirror of
https://github.com/edcommonwealth/sqm-dashboards.git
synced 2026-03-07 21:48:16 -08:00
Compute the score for a given construct, school, and academic year
This commit is contained in:
parent
9007cd3078
commit
1782ef3482
14 changed files with 160 additions and 63 deletions
|
|
@ -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 district
|
||||
@district ||= school.district
|
||||
end
|
||||
|
||||
def school_slug
|
||||
params[:school_id]
|
||||
end
|
||||
|
||||
def district
|
||||
@district ||= @school.district
|
||||
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
|
||||
3
app/models/survey_item.rb
Normal file
3
app/models/survey_item.rb
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
class SurveyItem < ActiveRecord::Base
|
||||
belongs_to :construct
|
||||
end
|
||||
4
app/models/survey_response.rb
Normal file
4
app/models/survey_response.rb
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
class SurveyResponse < ActiveRecord::Base
|
||||
belongs_to :school
|
||||
belongs_to :survey_item
|
||||
end
|
||||
16
app/models/survey_response_aggregator.rb
Normal file
16
app/models/survey_response_aggregator.rb
Normal file
|
|
@ -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
|
||||
10
db/migrate/20210915183344_create_survey_items.rb
Normal file
10
db/migrate/20210915183344_create_survey_items.rb
Normal file
|
|
@ -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
|
||||
13
db/migrate/20210916143538_create_survey_responses.rb
Normal file
13
db/migrate/20210916143538_create_survey_responses.rb
Normal file
|
|
@ -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
|
||||
23
db/schema.rb
23
db/schema.rb
|
|
@ -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
|
||||
7
spec/models/survey_item_spec.rb
Normal file
7
spec/models/survey_item_spec.rb
Normal file
|
|
@ -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
|
||||
60
spec/models/survey_response_aggregator_spec.rb
Normal file
60
spec/models/survey_response_aggregator_spec.rb
Normal file
|
|
@ -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…
Add table
Add a link
Reference in a new issue