Change race score calculations so the average bubbles up through survey_items

-> scales -> measure.
Precalculate averages for performance.
This commit is contained in:
rebuilt 2022-08-08 21:15:57 -07:00
parent 3f2279e2e8
commit 105f30f220
26 changed files with 379 additions and 84 deletions

View file

@ -56,9 +56,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add page caching - Add page caching
- Add counter caches - Add counter caches
- Detect the latest year for which a school has data and direct a user to that year when routing from welcome page - Detect the latest year for which a school has data and direct a user to that year when routing from welcome page
- Modify behavior of insufficient data indicators for admin data items. Now we show indicators in line with the admin data item descriptions to indicate which items are missing data
- Add student demographic data to the database
+ `bundle exec rake data:load_students`
- Add students by group graph on analyze page
- Precalculate race scores for analyze page
+ `bundle exec rake one_off:reset_race_scores` : limit which years/schools/measures/races are processed
+ `bundle exec rake data:reset_race_scores` : reset all race scores
## [Unreleased] ## [Unreleased]
### Added ### Added
- Modify behavior of insufficient data indicators for admin data items. Now we show indicators in line with the admin data item descriptions to indicate which items are missing data

View file

@ -147,7 +147,7 @@ class Measure < ActiveRecord::Base
def collect_survey_item_average(survey_items:, school:, academic_year:) def collect_survey_item_average(survey_items:, school:, academic_year:)
@collect_survey_item_average ||= Hash.new do |memo, (survey_items, school, academic_year)| @collect_survey_item_average ||= Hash.new do |memo, (survey_items, school, academic_year)|
averages = survey_items.map do |survey_item| averages = survey_items.map do |survey_item|
grouped_responses(school:, academic_year:)[survey_item] grouped_responses(school:, academic_year:)[survey_item.id]
end.remove_blanks end.remove_blanks
memo[[survey_items, school, academic_year]] = averages.average || 0 memo[[survey_items, school, academic_year]] = averages.average || 0
end end
@ -169,7 +169,7 @@ class Measure < ActiveRecord::Base
def grouped_responses(school:, academic_year:) def grouped_responses(school:, academic_year:)
@grouped_responses ||= Hash.new do |memo, (school, academic_year)| @grouped_responses ||= Hash.new do |memo, (school, academic_year)|
memo[[school, academic_year]] = memo[[school, academic_year]] =
SurveyItemResponse.where(school:, academic_year:).group(:survey_item).average(:likert_score) SurveyItemResponse.where(school:, academic_year:).group(:survey_item_id).average(:likert_score)
end end
@grouped_responses[[school, academic_year]] @grouped_responses[[school, academic_year]]
end end

6
app/models/race_score.rb Normal file
View file

@ -0,0 +1,6 @@
class RaceScore < ApplicationRecord
belongs_to :measure
belongs_to :school
belongs_to :academic_year
belongs_to :race
end

View file

@ -0,0 +1,17 @@
# frozen_string_literal: true
class RaceScoreCalculator
include Analyze::Graph::Column::RacialScore
attr_reader :measure, :school, :academic_year, :race
def initialize(measure:, school:, academic_year:, race:)
@measure = measure
@school = school
@academic_year = academic_year
@race = race
end
def score
race_score(measure:, school:, academic_year:, race:)
end
end

12
app/models/sample.rb Normal file
View file

@ -0,0 +1,12 @@
class Sample
attr_reader :school, :academic_year, :category, :measure, :race
def initialize
@school = School.find_by_slug 'milford-high-school'
@academic_year = AcademicYear.last
@category = Category.find_by_category_id '1'
@subcategory = Subcategory.find_by_subcategory_id '1A'
@measure = Measure.find_by_measure_id '1A-ii'
@race = Race.find_by_qualtrics_code 1
end
end

View file

@ -1,7 +1,7 @@
class Student < ApplicationRecord class Student < ApplicationRecord
has_many :survey_item_responses has_many :survey_item_responses
has_many :student_races has_many :student_races
has_many :races, through: :student_races has_and_belongs_to_many :races, join_table: :student_races
encrypts :lasid, deterministic: true encrypts :lasid, deterministic: true
end end

View file

@ -4,9 +4,8 @@ module Analyze
module Graph module Graph
module Column module Column
class AmericanIndian < GroupedBarColumnPresenter class AmericanIndian < GroupedBarColumnPresenter
include Analyze::Graph::Column::RaceScore include Analyze::Graph::Column::ScoreForRace
def label def label
# TODO: offset labels so they don't overlap
'American Indian' 'American Indian'
end end
@ -15,20 +14,13 @@ module Analyze
end end
def show_irrelevancy_message? def show_irrelevancy_message?
# !measure.includes_student_survey_items?
false false
end end
def show_insufficient_data_message? def show_insufficient_data_message?
# TODO: implement this logic. Resize messages so they are bound to their column
false false
end end
def score(year_index)
# TODO: make sure the score calculation bubble up instead of just average
race_score(measure:, school:, academic_year: academic_years[year_index], race:)
end
def race def race
Race.find_by_qualtrics_code 1 Race.find_by_qualtrics_code 1
end end

View file

@ -4,7 +4,7 @@ module Analyze
module Graph module Graph
module Column module Column
class Asian < GroupedBarColumnPresenter class Asian < GroupedBarColumnPresenter
include Analyze::Graph::Column::RaceScore include Analyze::Graph::Column::ScoreForRace
def label def label
'Asian' 'Asian'
end end
@ -14,7 +14,6 @@ module Analyze
end end
def show_irrelevancy_message? def show_irrelevancy_message?
# !measure.includes_student_survey_items?
false false
end end
@ -22,10 +21,6 @@ module Analyze
false false
end end
def score(year_index)
race_score(measure:, school:, academic_year: academic_years[year_index], race:)
end
def race def race
Race.find_by_qualtrics_code 2 Race.find_by_qualtrics_code 2
end end

View file

@ -4,7 +4,7 @@ module Analyze
module Graph module Graph
module Column module Column
class Black < GroupedBarColumnPresenter class Black < GroupedBarColumnPresenter
include Analyze::Graph::Column::RaceScore include Analyze::Graph::Column::ScoreForRace
def label def label
'Black' 'Black'
end end
@ -14,7 +14,6 @@ module Analyze
end end
def show_irrelevancy_message? def show_irrelevancy_message?
# !measure.includes_student_survey_items?
false false
end end
@ -22,10 +21,6 @@ module Analyze
false false
end end
def score(year_index)
race_score(measure:, school:, academic_year: academic_years[year_index], race:)
end
def race def race
Race.find_by_qualtrics_code 3 Race.find_by_qualtrics_code 3
end end

View file

@ -4,7 +4,7 @@ module Analyze
module Graph module Graph
module Column module Column
class Hispanic < GroupedBarColumnPresenter class Hispanic < GroupedBarColumnPresenter
include Analyze::Graph::Column::RaceScore include Analyze::Graph::Column::ScoreForRace
def label def label
'Hispanic' 'Hispanic'
end end
@ -14,7 +14,6 @@ module Analyze
end end
def show_irrelevancy_message? def show_irrelevancy_message?
# !measure.includes_student_survey_items?
false false
end end
@ -22,10 +21,6 @@ module Analyze
false false
end end
def score(year_index)
race_score(measure:, school:, academic_year: academic_years[year_index], race:)
end
def race def race
Race.find_by_qualtrics_code 4 Race.find_by_qualtrics_code 4
end end

View file

@ -4,7 +4,8 @@ module Analyze
module Graph module Graph
module Column module Column
class MiddleEastern < GroupedBarColumnPresenter class MiddleEastern < GroupedBarColumnPresenter
include Analyze::Graph::Column::RaceScore include Analyze::Graph::Column::ScoreForRace
def label def label
'Middle Eastern' 'Middle Eastern'
end end
@ -14,7 +15,6 @@ module Analyze
end end
def show_irrelevancy_message? def show_irrelevancy_message?
# !measure.includes_student_survey_items?
false false
end end
@ -22,10 +22,6 @@ module Analyze
false false
end end
def score(year_index)
race_score(measure:, school:, academic_year: academic_years[year_index], race:)
end
def race def race
Race.find_by_qualtrics_code 8 Race.find_by_qualtrics_code 8
end end

View file

@ -4,9 +4,8 @@ module Analyze
module Graph module Graph
module Column module Column
class Multiracial < GroupedBarColumnPresenter class Multiracial < GroupedBarColumnPresenter
include Analyze::Graph::Column::RaceScore include Analyze::Graph::Column::ScoreForRace
def label def label
# TODO: offset labels so they don't overlap
'Multiracial' 'Multiracial'
end end
@ -15,20 +14,13 @@ module Analyze
end end
def show_irrelevancy_message? def show_irrelevancy_message?
# !measure.includes_student_survey_items?
false false
end end
def show_insufficient_data_message? def show_insufficient_data_message?
# TODO: implement this logic. Resize messages so they are bound to their column
false false
end end
def score(year_index)
# TODO: make sure the score calculation bubble up instead of just average
race_score(measure:, school:, academic_year: academic_years[year_index], race:)
end
def race def race
Race.find_by_qualtrics_code 100 Race.find_by_qualtrics_code 100
end end

View file

@ -1,20 +0,0 @@
# frozen_string_literal: true
module Analyze
module Graph
module Column
module RaceScore
def race_score(measure:, school:, academic_year:, race:)
survey_items = measure.student_survey_items
students = StudentRace.where(race:).pluck(:student_id)
average = SurveyItemResponse.where(school:,
academic_year:,
survey_item: survey_items,
student: students)
.average(:likert_score)
Score.new(average, true, true, true)
end
end
end
end
end

View file

@ -0,0 +1,72 @@
# frozen_string_literal: true
module Analyze
module Graph
module Column
module RacialScore
def race_score(measure:, school:, academic_year:, race:)
rate = response_rate(school:, academic_year:, measure:)
return Score.new(0, false, false, false) unless rate.meets_student_threshold
survey_items = measure.student_survey_items
students = StudentRace.where(race:).pluck(:student_id).uniq
averages = grouped_responses(school:, academic_year:, survey_items:, students:)
number_of_responses = total_responses(school:, academic_year:, students:, survey_items:)
scorify(responses: averages, number_of_responses:)
end
private
def grouped_responses(school:, academic_year:, survey_items:, students:)
SurveyItemResponse.where(school:,
academic_year:,
student: students,
survey_item: survey_items)
.group(:survey_item_id)
.average(:likert_score)
end
def total_responses(school:, academic_year:, students:, survey_items:)
@total_responses ||= SurveyItemResponse.where(school:,
academic_year:,
student: students,
survey_item: survey_items).count
end
def response_rate(school:, academic_year:, measure:)
@response_rate ||= Hash.new do |memo, (school, academic_year)|
memo[[school, academic_year]] =
ResponseRate.find_by(subcategory: measure.subcategory, school:, academic_year:)
end
@response_rate[[school, academic_year]]
end
def scorify(responses:, number_of_responses:)
averages = bubble_up_averages(responses:)
average = averages.average
meets_student_threshold = sufficient_responses(averages:, number_of_responses:)
average = 0 unless meets_student_threshold
Score.new(average, false, meets_student_threshold, false)
end
def sufficient_responses(averages:, number_of_responses:)
total_questions = averages.count
average_num_of_responses = number_of_responses.to_f / total_questions
meets_student_threshold = average_num_of_responses >= 10
end
def bubble_up_averages(responses:)
measure.student_scales.map do |scale|
scale.survey_items.map do |survey_item|
responses[survey_item.id]
end.remove_blanks.average
end.remove_blanks
end
end
end
end
end

View file

@ -0,0 +1,16 @@
module Analyze
module Graph
module Column
module ScoreForRace
def score(year_index)
s = ::RaceScore.find_by(measure:, school:, academic_year: academic_years[year_index], race:)
average = s.average unless s.nil?
average ||= 0
meets_student_threshold = s.meets_student_threshold? unless s.nil?
meets_student_threshold ||= false
Score.new(average, false, meets_student_threshold, false)
end
end
end
end
end

View file

@ -4,7 +4,7 @@ module Analyze
module Graph module Graph
module Column module Column
class Unknown < GroupedBarColumnPresenter class Unknown < GroupedBarColumnPresenter
include Analyze::Graph::Column::RaceScore include Analyze::Graph::Column::ScoreForRace
def label def label
'Unknown' 'Unknown'
end end
@ -14,7 +14,6 @@ module Analyze
end end
def show_irrelevancy_message? def show_irrelevancy_message?
# !measure.includes_student_survey_items?
false false
end end
@ -22,10 +21,6 @@ module Analyze
false false
end end
def score(year_index)
race_score(measure:, school:, academic_year: academic_years[year_index], race:)
end
def race def race
Race.find_by_qualtrics_code 99 Race.find_by_qualtrics_code 99
end end

View file

@ -4,7 +4,7 @@ module Analyze
module Graph module Graph
module Column module Column
class White < GroupedBarColumnPresenter class White < GroupedBarColumnPresenter
include Analyze::Graph::Column::RaceScore include Analyze::Graph::Column::ScoreForRace
def label def label
'White' 'White'
end end
@ -14,7 +14,6 @@ module Analyze
end end
def show_irrelevancy_message? def show_irrelevancy_message?
# !measure.includes_student_survey_items?
false false
end end
@ -22,10 +21,6 @@ module Analyze
false false
end end
def score(year_index)
race_score(measure:, school:, academic_year: academic_years[year_index], race:)
end
def race def race
Race.find_by_qualtrics_code 5 Race.find_by_qualtrics_code 5
end end

View file

@ -0,0 +1,29 @@
class RaceScoreLoader
def self.reset(schools: School.all, academic_years: AcademicYear.all, measures: Measure.all, races: Race.all)
RaceScore.where(school: schools, academic_year: academic_years, measure: measures, race: races).delete_all
scores = []
measures.each do |measure|
schools.each do |school|
academic_years.each do |academic_year|
races.each do |race|
scores << process_score(measure:, school:, academic_year:, race:)
end
end
end
end
RaceScore.import scores, batch_size: 1000
end
private
def self.process_score(measure:, school:, academic_year:, race:)
score = RaceScoreCalculator.new(measure:, school:, academic_year:, race:).score
rs = RaceScore.find_by(measure:, school:, academic_year:, race:)
rs ||= RaceScore.new(measure:, school:, academic_year:, race:)
rs.average = score.average
rs.meets_student_threshold = score.meets_student_threshold?
rs
end
private_class_method :process_score
end

View file

@ -0,0 +1,14 @@
class CreateRaceScores < ActiveRecord::Migration[7.0]
def change
create_table :race_scores do |t|
t.references :measure, null: false, foreign_key: true
t.references :school, null: false, foreign_key: true
t.references :academic_year, null: false, foreign_key: true
t.references :race, null: false, foreign_key: true
t.float :average
t.boolean :meets_student_threshold
t.timestamps
end
end
end

View file

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.0].define(version: 2022_07_28_232445) do ActiveRecord::Schema[7.0].define(version: 2022_08_09_213959) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "pg_stat_statements" enable_extension "pg_stat_statements"
enable_extension "plpgsql" enable_extension "plpgsql"
@ -290,6 +290,21 @@ ActiveRecord::Schema[7.0].define(version: 2022_07_28_232445) do
t.index ["subcategory_id"], name: "index_measures_on_subcategory_id" t.index ["subcategory_id"], name: "index_measures_on_subcategory_id"
end end
create_table "race_scores", force: :cascade do |t|
t.bigint "measure_id", null: false
t.bigint "school_id", null: false
t.bigint "academic_year_id", null: false
t.bigint "race_id", null: false
t.float "average"
t.boolean "meets_student_threshold"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["academic_year_id"], name: "index_race_scores_on_academic_year_id"
t.index ["measure_id"], name: "index_race_scores_on_measure_id"
t.index ["race_id"], name: "index_race_scores_on_race_id"
t.index ["school_id"], name: "index_race_scores_on_school_id"
end
create_table "races", force: :cascade do |t| create_table "races", force: :cascade do |t|
t.string "designation" t.string "designation"
t.integer "qualtrics_code" t.integer "qualtrics_code"
@ -428,6 +443,10 @@ ActiveRecord::Schema[7.0].define(version: 2022_07_28_232445) do
add_foreign_key "legacy_school_categories", "legacy_categories", column: "category_id" add_foreign_key "legacy_school_categories", "legacy_categories", column: "category_id"
add_foreign_key "legacy_school_categories", "legacy_schools", column: "school_id" add_foreign_key "legacy_school_categories", "legacy_schools", column: "school_id"
add_foreign_key "measures", "subcategories" add_foreign_key "measures", "subcategories"
add_foreign_key "race_scores", "academic_years"
add_foreign_key "race_scores", "measures"
add_foreign_key "race_scores", "races"
add_foreign_key "race_scores", "schools"
add_foreign_key "respondents", "academic_years" add_foreign_key "respondents", "academic_years"
add_foreign_key "respondents", "schools" add_foreign_key "respondents", "schools"
add_foreign_key "response_rates", "academic_years" add_foreign_key "response_rates", "academic_years"

View file

@ -57,6 +57,14 @@ namespace :data do
puts "=====================> Completed loading #{ResponseRate.count} survey responses" puts "=====================> Completed loading #{ResponseRate.count} survey responses"
end end
desc 'reset race score calculations'
task reset_race_scores: :environment do
puts 'Resetting race scores'
RaceScoreLoader.reset
Rails.cache.clear
puts "=====================> Completed loading #{RaceScore.count} survey responses"
end
desc 'load admin_data' desc 'load admin_data'
task load_admin_data: :environment do task load_admin_data: :environment do
Dir.glob(Rails.root.join('data', 'admin_data', '*.csv')).each do |filepath| Dir.glob(Rails.root.join('data', 'admin_data', '*.csv')).each do |filepath|

View file

@ -106,6 +106,14 @@ namespace :one_off do
puts "=====================> Completed recalculating #{ResponseRate.count} response rates" puts "=====================> Completed recalculating #{ResponseRate.count} response rates"
end end
desc 'reset race score calculations'
task reset_race_scores: :environment do
puts 'Resetting race scores'
RaceScoreLoader.reset(academic_years: [AcademicYear.find_by_range('2021-22')])
Rails.cache.clear
puts "=====================> Completed loading #{RaceScore.count} survey responses"
end
desc 'list scales that have no survey responses' desc 'list scales that have no survey responses'
task list_scales_that_lack_survey_responses: :environment do task list_scales_that_lack_survey_responses: :environment do
output = AcademicYear.all.map do |academic_year| output = AcademicYear.all.map do |academic_year|

View file

@ -1,4 +1,18 @@
FactoryBot.define do FactoryBot.define do
factory :race_score do
measure { nil }
school { nil }
academic_year { nil }
race { nil }
average { 1.5 }
meets_student_threshold { false }
end
factory :student do
response_id { "ID#{rand}" }
lasid { "Lasid#{rand}" }
end
factory :student_race do factory :student_race do
student { nil } student { nil }
race { nil } race { nil }
@ -81,11 +95,13 @@ FactoryBot.define do
measure_id { rand.to_s } measure_id { rand.to_s }
name { 'A Measure' } name { 'A Measure' }
subcategory subcategory
# trait :with_student_survey_items do trait :with_student_survey_items do
# after(:create) do |measure| after(:create) do |measure|
# measure.survey_items << build_list(:student_survey_item, 2) create(:student_scale, measure:) do |scale|
# end create_list(:student_survey_item, 2, scale:)
# end end
end
end
end end
factory :scale do factory :scale do

View file

@ -0,0 +1,41 @@
require 'rails_helper'
describe RaceScoreCalculator do
let(:measure) { create(:measure, :with_student_survey_items) }
let(:school) { create(:school) }
let(:academic_year) { create(:academic_year) }
let(:race) { create(:race) }
let(:student) do
s = create(:student)
s.races << race
s.save
s
end
let(:survey_item_1) { measure.survey_items[0] }
let(:survey_item_2) { measure.survey_items[1] }
let(:survey_item_3) { measure.survey_items[2] }
let(:response_rate) do
create(:response_rate, school:, academic_year:, subcategory: measure.subcategory, meets_student_threshold: true)
end
context 'when survey item responses exist' do
before :each do
response_rate
create(:survey_item_response, school:, academic_year:, likert_score: 1, survey_item: survey_item_1, student:)
create_list(:survey_item_response, 8, school:, academic_year:, likert_score: 2, survey_item: survey_item_1,
student:)
create(:survey_item_response, school:, academic_year:, likert_score: 3, survey_item: survey_item_1, student:)
create(:survey_item_response, school:, academic_year:, likert_score: 2, survey_item: survey_item_2, student:)
create_list(:survey_item_response, 8, school:, academic_year:, likert_score: 3, survey_item: survey_item_2,
student:)
create(:survey_item_response, school:, academic_year:, likert_score: 4, survey_item: survey_item_2, student:)
end
it 'returns a list of averages' do
expect(measure.student_survey_items.count).to eq 2
american_indian_score = RaceScoreCalculator.new(measure:, school:, academic_year:, race:).score
expect(american_indian_score).to eq Score.new(2.5, false, true, false)
end
end
end

View file

@ -0,0 +1,46 @@
require 'rails_helper'
include Analyze::Graph::Column
# RacialScore is a module used in the RaceScoreCalculator class
describe RacialScore do
let(:measure) { create(:measure, :with_student_survey_items) }
let(:school) { create(:school) }
let(:academic_year) { create(:academic_year) }
let(:race) { create(:race) }
let(:student) do
s = create(:student)
s.races << race
s.save
s
end
let(:survey_item_1) { measure.survey_items[0] }
let(:survey_item_2) { measure.survey_items[1] }
let(:survey_item_3) { measure.survey_items[2] }
let(:response_rate) do
create(:response_rate, school:, academic_year:, subcategory: measure.subcategory, meets_student_threshold: true)
end
context 'when survey item responses exist' do
before :each do
response_rate
create(:survey_item_response, school:, academic_year:, likert_score: 1, survey_item: survey_item_1, student:)
create_list(:survey_item_response, 8, school:, academic_year:, likert_score: 2, survey_item: survey_item_1,
student:)
create(:survey_item_response, school:, academic_year:, likert_score: 3, survey_item: survey_item_1, student:)
create(:survey_item_response, school:, academic_year:, likert_score: 2, survey_item: survey_item_2, student:)
create_list(:survey_item_response, 8, school:, academic_year:, likert_score: 3, survey_item: survey_item_2,
student:)
create(:survey_item_response, school:, academic_year:, likert_score: 4, survey_item: survey_item_2, student:)
end
it 'returns a list of averages' do
expect(measure.student_survey_items.count).to eq 2
students = StudentRace.where(race:).pluck(:student_id)
american_indian_score = RaceScoreCalculator.new(measure:, school:, academic_year:, race:).score
expect(american_indian_score).to eq Score.new(2.5, false, true, false)
end
end
end

View file

@ -0,0 +1,50 @@
require 'rails_helper'
describe RaceScoreLoader do
let(:measure) { create(:measure, :with_student_survey_items) }
let(:school) { create(:school) }
let(:academic_year) { create(:academic_year) }
let(:race) { create(:race) }
let(:student) do
s = create(:student)
s.races << race
s.save
s
end
let(:survey_item_1) { measure.survey_items[0] }
let(:survey_item_2) { measure.survey_items[1] }
let(:survey_item_3) { measure.survey_items[2] }
let(:response_rate) do
create(:response_rate, school:, academic_year:, subcategory: measure.subcategory, meets_student_threshold: true)
end
context 'when survey item responses exist' do
before :each do
response_rate
create(:survey_item_response, school:, academic_year:, likert_score: 1, survey_item: survey_item_1, student:)
create_list(:survey_item_response, 8, school:, academic_year:, likert_score: 2, survey_item: survey_item_1,
student:)
create(:survey_item_response, school:, academic_year:, likert_score: 3, survey_item: survey_item_1, student:)
create(:survey_item_response, school:, academic_year:, likert_score: 2, survey_item: survey_item_2, student:)
create_list(:survey_item_response, 8, school:, academic_year:, likert_score: 3, survey_item: survey_item_2,
student:)
create(:survey_item_response, school:, academic_year:, likert_score: 4, survey_item: survey_item_2, student:)
RaceScoreLoader.reset
end
it 'returns a list of averages' do
expect(measure.student_survey_items.count).to eq 2
american_indian_score = RaceScore.find_by(measure:, school:, academic_year:, race:)
expect(american_indian_score.average).to eq 2.5
expect(american_indian_score.meets_student_threshold).to eq true
end
it 'is idempotent' do
original_count = RaceScore.count
RaceScoreLoader.reset
new_count = RaceScore.count
expect(original_count).to eq new_count
end
end
end