ECP-125 feat:

Update cleaner to read parent races.
Update uploader to set races for parents.
Add race graphs to analyze page.  Show both measure and scale level graphs
This commit is contained in:
rebuilt 2025-05-15 18:07:28 -07:00
parent 76f2467b97
commit 5b00454a1b
15 changed files with 322 additions and 39 deletions

View file

@ -2,4 +2,5 @@ class Parent < ApplicationRecord
belongs_to :housing, optional: true belongs_to :housing, optional: true
has_many :parent_languages has_many :parent_languages
has_and_belongs_to_many :languages, join_table: :parent_languages has_and_belongs_to_many :languages, join_table: :parent_languages
has_and_belongs_to_many :races, join_table: :parent_races
end end

View file

@ -51,6 +51,17 @@ class SurveyItemResponse < ActiveRecord::Base
).where("student_races.race_id": race.id).group(:survey_item).having("count(*) >= 10").average(:likert_score) ).where("student_races.race_id": race.id).group(:survey_item).having("count(*) >= 10").average(:likert_score)
} }
scope :averages_for_parent_race, lambda { |survey_items, school, academic_year, race|
id = if race.instance_of? ::Race
race.id
else
race.map(&:id)
end
SurveyItemResponse.joins("JOIN parent_races on survey_item_responses.parent_id = parent_races.parent_id JOIN parents on parents.id = parent_races.parent_id").where(
school:, academic_year:, survey_item: survey_items
).where("parent_races.race_id": id).group(:survey_item).having("count(*) >= 10").average(:likert_score)
}
scope :averages_for_language, lambda { |survey_items, school, academic_year, designations| scope :averages_for_language, lambda { |survey_items, school, academic_year, designations|
SurveyItemResponse.joins([parent: :languages]).where(languages: { designation: designations }, survey_item: survey_items, school:, academic_year:).group(:survey_item).average(:likert_score) SurveyItemResponse.joins([parent: :languages]).where(languages: { designation: designations }, survey_item: survey_items, school:, academic_year:).group(:survey_item).average(:likert_score)
} }

View file

@ -17,10 +17,6 @@ module Analyze
"parent surveys" "parent surveys"
end end
def show_irrelevancy_message?(construct:)
false
end
def show_insufficient_data_message?(construct:, school:, academic_years:) def show_insufficient_data_message?(construct:, school:, academic_years:)
false false
end end

View file

@ -0,0 +1,74 @@
# frozen_string_literal: true
module Analyze
module Graph
module Column
module Parent
class Race < ColumnBase
attr_reader :race, :label
def initialize(races:, label:, show_irrelevancy_message:)
@race = races
@label = label
@show_irrelevancy_message = show_irrelevancy_message
end
def basis
"parent surveys"
end
def show_insufficient_data_message?(construct:, school:, academic_years:)
false
end
def type
:parent
end
def n_size(construct:, school:, academic_year:)
designation = if race.instance_of? ::Race
race.designation
else
race.map(&:designation)
end
SurveyItemResponse.joins([parent: :races]).where(races: { designation: }, survey_item: construct.parent_survey_items, school:, academic_year:).select(:parent_id).distinct.count
end
def score(construct:, school:, academic_year:)
return Score::NIL_SCORE if n_size(construct:, school:, academic_year:) < 10
averages = SurveyItemResponse.averages_for_parent_race(construct.parent_survey_items, school, academic_year, race)
average = bubble_up_averages(construct:, averages:).round(2)
Score.new(average:,
meets_teacher_threshold: false,
meets_student_threshold: true,
meets_admin_data_threshold: false)
end
def bubble_up_averages(construct:, averages:)
name = construct.class.name.downcase
send("#{name}_bubble_up_averages", construct:, averages:)
end
def measure_bubble_up_averages(construct:, averages:)
construct.parent_scales.map do |scale|
scale_bubble_up_averages(construct: scale, averages:)
end.remove_blanks.average
end
def scale_bubble_up_averages(construct:, averages:)
construct.survey_items.map do |survey_item|
averages[survey_item]
end.remove_blanks.average
end
def show_irrelevancy_message?(construct:)
return false if @show_irrelevancy_message == false
construct.survey_items.parent_survey_items.count.zero?
end
end
end
end
end
end

View file

@ -0,0 +1,42 @@
# frozen_string_literal: true
module Analyze
module Graph
class ParentsByRace
def to_s
"Parents by Race"
end
def slug
"parents-by-race"
end
def columns
[].tap do |array|
Race.all.each do |race|
label = if race.designation.match(/\or\s/i)
[race.designation.split("or").first.squish]
else
race.designation.split(" ", 2).compact
end
array << Analyze::Graph::Column::Parent::Race.new(races: race, label:, show_irrelevancy_message: false)
end
array << Analyze::Graph::Column::Parent::Race.new(races: Race.all, label: ["All Parent"], show_irrelevancy_message: true)
end
end
def source
Analyze::Source::SurveyData.new(slices: nil, graph: self)
end
def slice
Analyze::Slice::ParentsByGroup.new(graph: self)
end
def group
Analyze::Group::Base.new(name: "Race", slug: "race", graph: self)
end
end
end
end

View file

@ -139,7 +139,7 @@ module Analyze
def show_scale_level_graphs?(measure:) def show_scale_level_graphs?(measure:)
return false unless measure.includes_parent_survey_items? return false unless measure.includes_parent_survey_items?
["parents-by-language"].include?(requested_graphs) requested_graphs.starts_with? "parents-by"
end end
def sources def sources
@ -162,7 +162,8 @@ module Analyze
"students-by-income" => Analyze::Graph::StudentsByIncome.new(incomes: selected_incomes), "students-by-income" => Analyze::Graph::StudentsByIncome.new(incomes: selected_incomes),
"students-by-sped" => Analyze::Graph::StudentsBySped.new(speds: selected_speds), "students-by-sped" => Analyze::Graph::StudentsBySped.new(speds: selected_speds),
"students-by-ell" => Analyze::Graph::StudentsByEll.new(ells: selected_ells), "students-by-ell" => Analyze::Graph::StudentsByEll.new(ells: selected_ells),
"parents-by-language" => Analyze::Graph::ParentsByLanguage.new } "parents-by-language" => Analyze::Graph::ParentsByLanguage.new,
"parents-by-race" => Analyze::Graph::ParentsByRace.new }
end end
def scale_level_graphs def scale_level_graphs
@ -175,7 +176,8 @@ module Analyze
"students-by-income" => nil, "students-by-income" => nil,
"students-by-sped" => nil, "students-by-sped" => nil,
"students-by-ell" => nil, "students-by-ell" => nil,
"parents-by-language" => Analyze::Graph::ParentsByLanguage.new } "parents-by-language" => Analyze::Graph::ParentsByLanguage.new,
"parents-by-race" => Analyze::Graph::ParentsByRace.new }
end end
def graphs def graphs

View file

@ -79,7 +79,7 @@ class Cleaner
headers = headers.to_set headers = headers.to_set
headers = headers.merge(Set.new(["Raw Income", "Income", "Raw ELL", "ELL", "Raw SpEd", "SpEd", "Progress Count", headers = headers.merge(Set.new(["Raw Income", "Income", "Raw ELL", "ELL", "Raw SpEd", "SpEd", "Progress Count",
"Race", "Gender", "Raw Housing Status", "Housing Status", "Home Language", "Home Languages"])).to_a "Race", "Gender", "Raw Housing Status", "Housing Status", "Home Language", "Home Languages", "Declared Races of Children from Parents"])).to_a
filtered_headers = include_all_headers(headers:) filtered_headers = include_all_headers(headers:)
filtered_headers = remove_unwanted_headers(headers: filtered_headers) filtered_headers = remove_unwanted_headers(headers: filtered_headers)
log_headers = (filtered_headers + ["Valid Duration?", "Valid Progress?", "Valid Grade?", log_headers = (filtered_headers + ["Valid Duration?", "Valid Progress?", "Valid Grade?",

View file

@ -11,21 +11,26 @@ class SurveyItemValues
@academic_years = academic_years @academic_years = academic_years
copy_likert_scores_from_variant_survey_items copy_likert_scores_from_variant_survey_items
row["Income"] = income if survey_type == :student
row["Raw Income"] = raw_income row["Income"] = income
row["Raw ELL"] = raw_ell row["Raw Income"] = raw_income
row["ELL"] = ell row["Raw ELL"] = raw_ell
row["Raw SpEd"] = raw_sped row["ELL"] = ell
row["SpEd"] = sped row["Raw SpEd"] = raw_sped
row["Progress Count"] = progress row["SpEd"] = sped
row["Race"] ||= races.join(",") row["Progress Count"] = progress
row["Gender"] ||= gender row["Race"] ||= races.join(",")
row["Gender"] ||= gender
copy_data_to_main_column(main: /Race/i, secondary: /Race Secondary|Race-1/i)
copy_data_to_main_column(main: /Gender/i, secondary: /Gender Secondary|Gender-1/i)
end
return unless survey_type == :parent
row["Raw Housing Status"] = raw_housing row["Raw Housing Status"] = raw_housing
row["Housing Status"] = housing row["Housing Status"] = housing
row["Home Languages"] = languages.join(",") row["Home Languages"] = languages.join(",")
row["Declared Races of Children from Parents"] = races_of_children.join(",")
copy_data_to_main_column(main: /Race/i, secondary: /Race Secondary|Race-1/i)
copy_data_to_main_column(main: /Gender/i, secondary: /Gender Secondary|Gender-1/i)
end end
def normalize_headers(headers:) def normalize_headers(headers:)
@ -170,6 +175,21 @@ class SurveyItemValues
end end
end end
def races_of_children
race_codes = []
matches = headers.select do |header|
header.match(/^Race$|^Race-\d+/i)
end
matches.each do |match|
row[match]&.split(",")&.each do |item|
race_codes << item&.strip&.to_i
end
end
Race.normalize_race_list(race_codes.sort)
end
def lasid def lasid
@lasid ||= value_from(pattern: /LASID/i) || "" @lasid ||= value_from(pattern: /LASID/i) || ""
end end

View file

@ -113,6 +113,11 @@ class SurveyResponsesDataLoader
tmp_languages = row.languages.map { |language| languages[language] }.reject(&:nil?) tmp_languages = row.languages.map { |language| languages[language] }.reject(&:nil?)
parent.languages.delete_all parent.languages.delete_all
parent.languages.concat(tmp_languages) parent.languages.concat(tmp_languages)
parent.races.delete_all
tmp_races = row.races_of_children.map { |race| races[race] }.reject(&:nil?)
parent.races.concat(tmp_races)
parent.housing = housings[row.housing] if row.housing.present? parent.housing = housings[row.housing] if row.housing.present?
parent.save parent.save
end end

View file

@ -0,0 +1,10 @@
class CreateParentRaces < ActiveRecord::Migration[8.0]
def change
create_table :parent_races do |t|
t.references :parent, null: false, foreign_key: true
t.references :race, null: false, foreign_key: true
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[8.0].define(version: 2025_04_18_185655) do ActiveRecord::Schema[8.0].define(version: 2025_05_15_205734) 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_catalog.plpgsql" enable_extension "pg_catalog.plpgsql"
@ -340,6 +340,15 @@ ActiveRecord::Schema[8.0].define(version: 2025_04_18_185655) do
t.index ["parent_id"], name: "index_parent_languages_on_parent_id" t.index ["parent_id"], name: "index_parent_languages_on_parent_id"
end end
create_table "parent_races", force: :cascade do |t|
t.bigint "parent_id", null: false
t.bigint "race_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["parent_id"], name: "index_parent_races_on_parent_id"
t.index ["race_id"], name: "index_parent_races_on_race_id"
end
create_table "parents", force: :cascade do |t| create_table "parents", force: :cascade do |t|
t.string "response_id" t.string "response_id"
t.integer "number_of_children" t.integer "number_of_children"
@ -536,6 +545,8 @@ ActiveRecord::Schema[8.0].define(version: 2025_04_18_185655) do
add_foreign_key "measures", "subcategories" add_foreign_key "measures", "subcategories"
add_foreign_key "parent_languages", "languages" add_foreign_key "parent_languages", "languages"
add_foreign_key "parent_languages", "parents" add_foreign_key "parent_languages", "parents"
add_foreign_key "parent_races", "parents"
add_foreign_key "parent_races", "races"
add_foreign_key "parents", "housings" add_foreign_key "parents", "housings"
add_foreign_key "respondents", "academic_years" add_foreign_key "respondents", "academic_years"
add_foreign_key "respondents", "schools" add_foreign_key "respondents", "schools"

View file

@ -1,8 +1,9 @@
StartDate,EndDate,Status,IPAddress,Progress,Duration (in seconds),Finished,RecordedDate,ResponseId,DistributionChannel,UserLanguage,DESE ID,Number of Children,Gender-1,Gender-1_7_TEXT,Race-1,Race-1_7_TEXT,Gender-2,Gender-2_7_TEXT,Race-2,Race-2_7_TEXT,Gender-3,Gender-3_7_TEXT,Race-3,Race-3_7_TEXT,Gender-4,Gender-4_7_TEXT,Race-4,Race-4_7_TEXT,Gender-5,Gender-5_7_TEXT,Race-5,Race-5_7_TEXT,Gender,Gender_7_TEXT,p-scrp-q3,p-scrp-q2,p-valm-q1,p-valm-q2,p-valm-q3,p-valm-q4,p-comm-q1,p-comm-q2,p-comm-q3,p-tcom-q1,P-tcom-q2,p-tcom-q3,p-evnt-q4,p-comm-q4,p-evnt-q3,p-evnt-q1,p-evnt-q2,p-socx-q3,p-socx-q4,p-scrp-q1,p-socx-q1,p-sosu-q1,p-sosu-q2,p-sosu-q3,p-socx-q2,p-sosu-q4,p-phys-q3,p-acpr-q1,p-acpr-q2,p-acpr-q3,p-acpr-q4,p-cure-q1,p-cure-q2,p-cure-q3,p-cure-q4,Housing,Housing_100_TEXT,Employment,Employment_100_TEXT,Caregivers,Caregivers_100_TEXT,Education,Education_100_TEXT,Benefits,Benefits_100_TEXT,Language,Language_100_TEXT,Raw Income,Income,Raw ELL,ELL,Raw SpEd,SpEd,Progress Count,Race StartDate,EndDate,Status,IPAddress,Progress,Duration (in seconds),Finished,RecordedDate,ResponseId,DistributionChannel,UserLanguage,DESE ID,Number of Children,Gender-1,Gender-1_7_TEXT,Race-1,Race-1_7_TEXT,Gender-2,Gender-2_7_TEXT,Race-2,Race-2_7_TEXT,Gender-3,Gender-3_7_TEXT,Race-3,Race-3_7_TEXT,Gender-4,Gender-4_7_TEXT,Race-4,Race-4_7_TEXT,Gender-5,Gender-5_7_TEXT,Race-5,Race-5_7_TEXT,Gender,Gender_7_TEXT,p-scrp-q3,p-scrp-q2,p-valm-q1,p-valm-q2,p-valm-q3,p-valm-q4,p-comm-q1,p-comm-q2,p-comm-q3,p-tcom-q1,P-tcom-q2,p-tcom-q3,p-evnt-q4,p-comm-q4,p-evnt-q3,p-evnt-q1,p-evnt-q2,p-socx-q3,p-socx-q4,p-scrp-q1,p-socx-q1,p-sosu-q1,p-sosu-q2,p-sosu-q3,p-socx-q2,p-sosu-q4,p-phys-q3,p-acpr-q1,p-acpr-q2,p-acpr-q3,p-acpr-q4,p-cure-q1,p-cure-q2,p-cure-q3,p-cure-q4,Housing,Housing_100_TEXT,Employment,Employment_100_TEXT,Caregivers,Caregivers_100_TEXT,Education,Education_100_TEXT,Benefits,Benefits_100_TEXT,Language,Language_100_TEXT,Raw Income,Income,Raw ELL,ELL,Raw SpEd,SpEd,Progress Count
5/1/2024 10:04:34,5/1/2024 10:10:49,0,72.93.86.98,100,374,1,2021-03-31T10:01:36,parent_survey_response_1,email,EN,1500025,1,,,,,,,,,,,,,,,,,,,,,2,,4,5,5,4,5,5,5,5,5,4,4,5,4,5,3,4,5,4,4,5,5,5,5,5,5,5,1,2,2,2,1,4,5,5,5,1,,1,,2,,5,,2,,1,,,Economically Disadvantaged - N,,Not ELL,,Not Special Education,34,99 5/1/2024 10:04:34,5/1/2024 10:10:49,0,72.93.86.98,100,374,1,2021-03-31T10:01:36,parent_survey_response_1,email,EN,1500025,1,,,1,,,,,,,,,,,,,,,,,,2,,4,5,5,4,5,5,5,5,5,4,4,5,4,5,3,4,5,4,4,5,5,5,5,5,5,5,1,2,2,2,1,4,5,5,5,1,,1,,2,,5,,2,,1,,,Economically Disadvantaged - N,,Not ELL,,Not Special Education,34
5/1/2024 10:03:52,5/1/2024 10:14:42,0,73.69.182.58,100,649,1,2021-04-01T10:01:36,parent_survey_response_2,email,EN,1500025,1,,,,,,,,,,,,,,,,,,,,,1,,4,4,5,5,5,5,5,5,5,5,5,5,3,5,4,5,5,5,5,5,4,4,4,4,5,5,1,5,4,5,5,5,5,5,5,1,,99,,2,,3,,1,,1,,,Economically Disadvantaged - N,,Not ELL,,Not Special Education,34,99 5/1/2024 10:03:52,5/1/2024 10:14:42,0,73.69.182.58,100,649,1,2021-04-01T10:01:36,parent_survey_response_2,email,EN,1500025,1,,,,,,,,,,,6,,,,7,,,,,,1,,4,4,5,5,5,5,5,5,5,5,5,5,3,5,4,5,5,5,5,5,4,4,4,4,5,5,1,5,4,5,5,5,5,5,5,1,,99,,2,,3,,1,,1,,,Economically Disadvantaged - N,,Not ELL,,Not Special Education,34
5/1/2024 10:06:44,5/1/2024 10:15:41,0,50.235.109.170,100,537,1,2021-04-02T10:01:36,parent_survey_response_3,email,EN,1500025,2,2,,5,,2,,5,,,,,,,,,,,,,,2,,5,5,5,4,5,5,5,5,5,4,4,5,4,4,3,4,4,4,4,5,4,4,5,5,2,5,3,4,4,4,4,5,5,5,5,1,,1,,3,,6,,2,,1,,,Economically Disadvantaged - N,,Not ELL,,Not Special Education,34,5 5/1/2024 10:06:44,5/1/2024 10:15:41,0,50.235.109.170,100,537,1,2021-04-02T10:01:36,parent_survey_response_3,email,EN,1500025,2,2,,4,,2,,"1,5",,,,,,,,,,,,,,2,,5,5,5,4,5,5,5,5,5,4,4,5,4,4,3,4,4,4,4,5,4,4,5,5,2,5,3,4,4,4,4,5,5,5,5,1,,1,,3,,6,,2,,1,,,Economically Disadvantaged - N,,Not ELL,,Not Special Education,34
5/1/2024 10:14:23,5/1/2024 10:22:22,0,73.38.238.192,100,478,1,2021-04-03T10:01:36,parent_survey_response_4,email,EN,1500025,1,,,,,,,,,,,,,,,,,,,,,1,,5,5,5,5,5,5,5,4,5,4,4,4,2,5,4,5,4,5,5,5,3,5,5,5,2,5,1,5,5,5,5,5,5,5,5,1,,1,,2,,5,,2,,1,,,Economically Disadvantaged - N,,Not ELL,,Not Special Education,34,99 5/1/2024 10:14:23,5/1/2024 10:22:22,0,73.38.238.192,100,478,1,2021-04-03T10:01:36,parent_survey_response_4,email,EN,1500025,1,,,,,,,,,,,,,,,,,,,,,1,,5,5,5,5,5,5,5,4,5,4,4,4,2,5,4,5,4,5,5,5,3,5,5,5,2,5,1,5,5,5,5,5,5,5,5,1,,1,,2,,5,,2,,1,,,Economically Disadvantaged - N,,Not ELL,,Not Special Education,34
5/1/2024 10:18:39,5/1/2024 10:23:49,0,73.69.158.255,100,310,1,2021-04-04T10:01:36,parent_survey_response_5,email,EN,1500025,2,2,,5,,1,,5,,,,,,,,,,,,,,2,,5,4,5,5,5,5,1,1,1,1,1,1,3,1,4,4,5,1,1,1,4,1,1,1,4,5,1,5,5,5,5,1,5,1,1,1,,"2,4",,3,,5,,2,,1,,,Economically Disadvantaged - N,,Not ELL,,Not Special Education,34,5 5/1/2024 10:18:39,5/1/2024 10:23:49,0,73.69.158.255,100,310,1,2021-04-04T10:01:36,parent_survey_response_5,email,EN,1500025,2,2,,"1,2,3",,1,,"4,5,8",,,,,,,,,,,,,,2,,5,4,5,5,5,5,1,1,1,1,1,1,3,1,4,4,5,1,1,1,4,1,1,1,4,5,1,5,5,5,5,1,5,1,1,1,,"2,4",,3,,5,,2,,1,,,Economically Disadvantaged - N,,Not ELL,,Not Special Education,34
5/1/2024 10:20:30,5/1/2024 10:25:16,0,73.182.146.201,100,285,1,2021-04-05T10:01:36,parent_survey_response_6,email,EN,1500025,1,,,,,,,,,,,,,,,,,,,,,1,,3,3,3,1,3,2,4,2,4,1,1,3,3,4,3,4,1,5,5,4,3,5,4,3,3,1,3,5,5,4,5,4,4,5,4,2,,2,,2,,5,,2,,1,,,Economically Disadvantaged - N,,Not ELL,,Not Special Education,34,99 5/1/2024 10:20:30,5/1/2024 10:25:16,0,73.182.146.201,100,285,1,2021-04-05T10:01:36,parent_survey_response_6,email,EN,1500025,1,,,,,,,,,,,,,,,1,,,,"2,3,4,5,8",,1,,3,3,3,1,3,2,4,2,4,1,1,3,3,4,3,4,1,5,5,4,3,5,4,3,3,1,3,5,5,4,5,4,4,5,4,2,,2,,2,,5,,2,,1,,,Economically Disadvantaged - N,,Not ELL,,Not Special Education,34
5/1/2024 10:14:01,5/1/2024 10:27:19,0,209.107.182.203,100,798,1,2021-04-06T10:01:36,parent_survey_response_7,email,EN,1500025,2,1,,5,,1,,5,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,1,,2,,5,,2,,1,,,Economically Disadvantaged - N,,Not ELL,,Not Special Education,34,5 5/1/2024 10:14:01,5/1/2024 10:27:19,0,209.107.182.203,100,798,1,2021-04-06T10:01:36,parent_survey_response_7,email,EN,1500025,2,1,,5,,1,,5,,,,,,,,,,,,,,1,,3,3,3,1,3,2,4,2,4,1,1,3,3,4,3,4,1,5,5,4,3,5,4,3,3,1,3,5,5,4,5,4,4,5,4,1,,1,,2,,5,,2,,1,,,Economically Disadvantaged - N,,Not ELL,,Not Special Education,34
5/1/2024 10:14:01,5/1/2024 10:27:19,0,209.107.182.203,100,798,1,2021-04-06T10:01:36,parent_survey_response_8,email,EN,1500025,2,1,,5,,1,,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,

1 StartDate EndDate Status IPAddress Progress Duration (in seconds) Finished RecordedDate ResponseId DistributionChannel UserLanguage DESE ID Number of Children Gender-1 Gender-1_7_TEXT Race-1 Race-1_7_TEXT Gender-2 Gender-2_7_TEXT Race-2 Race-2_7_TEXT Gender-3 Gender-3_7_TEXT Race-3 Race-3_7_TEXT Gender-4 Gender-4_7_TEXT Race-4 Race-4_7_TEXT Gender-5 Gender-5_7_TEXT Race-5 Race-5_7_TEXT Gender Gender_7_TEXT p-scrp-q3 p-scrp-q2 p-valm-q1 p-valm-q2 p-valm-q3 p-valm-q4 p-comm-q1 p-comm-q2 p-comm-q3 p-tcom-q1 P-tcom-q2 p-tcom-q3 p-evnt-q4 p-comm-q4 p-evnt-q3 p-evnt-q1 p-evnt-q2 p-socx-q3 p-socx-q4 p-scrp-q1 p-socx-q1 p-sosu-q1 p-sosu-q2 p-sosu-q3 p-socx-q2 p-sosu-q4 p-phys-q3 p-acpr-q1 p-acpr-q2 p-acpr-q3 p-acpr-q4 p-cure-q1 p-cure-q2 p-cure-q3 p-cure-q4 Housing Housing_100_TEXT Employment Employment_100_TEXT Caregivers Caregivers_100_TEXT Education Education_100_TEXT Benefits Benefits_100_TEXT Language Language_100_TEXT Raw Income Income Raw ELL ELL Raw SpEd SpEd Progress Count Race
2 5/1/2024 10:04:34 5/1/2024 10:10:49 0 72.93.86.98 100 374 1 2021-03-31T10:01:36 parent_survey_response_1 email EN 1500025 1 1 2 4 5 5 4 5 5 5 5 5 4 4 5 4 5 3 4 5 4 4 5 5 5 5 5 5 5 1 2 2 2 1 4 5 5 5 1 1 2 5 2 1 Economically Disadvantaged - N Not ELL Not Special Education 34 99
3 5/1/2024 10:03:52 5/1/2024 10:14:42 0 73.69.182.58 100 649 1 2021-04-01T10:01:36 parent_survey_response_2 email EN 1500025 1 6 7 1 4 4 5 5 5 5 5 5 5 5 5 5 3 5 4 5 5 5 5 5 4 4 4 4 5 5 1 5 4 5 5 5 5 5 5 1 99 2 3 1 1 Economically Disadvantaged - N Not ELL Not Special Education 34 99
4 5/1/2024 10:06:44 5/1/2024 10:15:41 0 50.235.109.170 100 537 1 2021-04-02T10:01:36 parent_survey_response_3 email EN 1500025 2 2 5 4 2 5 1,5 2 5 5 5 4 5 5 5 5 5 4 4 5 4 4 3 4 4 4 4 5 4 4 5 5 2 5 3 4 4 4 4 5 5 5 5 1 1 3 6 2 1 Economically Disadvantaged - N Not ELL Not Special Education 34 5
5 5/1/2024 10:14:23 5/1/2024 10:22:22 0 73.38.238.192 100 478 1 2021-04-03T10:01:36 parent_survey_response_4 email EN 1500025 1 1 5 5 5 5 5 5 5 4 5 4 4 4 2 5 4 5 4 5 5 5 3 5 5 5 2 5 1 5 5 5 5 5 5 5 5 1 1 2 5 2 1 Economically Disadvantaged - N Not ELL Not Special Education 34 99
6 5/1/2024 10:18:39 5/1/2024 10:23:49 0 73.69.158.255 100 310 1 2021-04-04T10:01:36 parent_survey_response_5 email EN 1500025 2 2 5 1,2,3 1 5 4,5,8 2 5 4 5 5 5 5 1 1 1 1 1 1 3 1 4 4 5 1 1 1 4 1 1 1 4 5 1 5 5 5 5 1 5 1 1 1 2,4 3 5 2 1 Economically Disadvantaged - N Not ELL Not Special Education 34 5
7 5/1/2024 10:20:30 5/1/2024 10:25:16 0 73.182.146.201 100 285 1 2021-04-05T10:01:36 parent_survey_response_6 email EN 1500025 1 1 2,3,4,5,8 1 3 3 3 1 3 2 4 2 4 1 1 3 3 4 3 4 1 5 5 4 3 5 4 3 3 1 3 5 5 4 5 4 4 5 4 2 2 2 5 2 1 Economically Disadvantaged - N Not ELL Not Special Education 34 99
8 5/1/2024 10:14:01 5/1/2024 10:27:19 0 209.107.182.203 100 798 1 2021-04-06T10:01:36 parent_survey_response_7 email EN 1500025 2 1 5 1 5 1 3 3 3 1 3 2 4 2 4 1 1 3 3 4 3 4 1 5 5 4 3 5 4 3 3 1 3 5 5 4 5 4 4 5 4 1 1 2 5 2 1 Economically Disadvantaged - N Not ELL Not Special Education 34 5
9 5/1/2024 10:14:01 5/1/2024 10:27:19 0 209.107.182.203 100 798 1 2021-04-06T10:01:36 parent_survey_response_8 email EN 1500025 2 1 5 1 5

View file

@ -315,7 +315,7 @@ def reads_headers_from_raw_csv(processed_data)
"s-grit-q1", "s-grit-q2", "s-grit-q3", "s-grit-q4", "s-expa-q1", "s-poaf-q1", "s-poaf-q2", "s-poaf-q3", "s-grit-q1", "s-grit-q2", "s-grit-q3", "s-grit-q4", "s-expa-q1", "s-poaf-q1", "s-poaf-q2", "s-poaf-q3",
"s-poaf-q4", "s-tint-q1-1", "s-tint-q2-1", "s-tint-q3-1", "s-tint-q4-1", "s-tint-q5-1", "s-acpr-q1-1", "s-poaf-q4", "s-tint-q1-1", "s-tint-q2-1", "s-tint-q3-1", "s-tint-q4-1", "s-tint-q5-1", "s-acpr-q1-1",
"s-acpr-q2-1", "s-acpr-q3-1", "s-acpr-q4-1", "s-peff-q1-1", "s-peff-q2-1", "s-peff-q3-1", "s-peff-q4-1", "s-acpr-q2-1", "s-acpr-q3-1", "s-acpr-q4-1", "s-peff-q1-1", "s-peff-q2-1", "s-peff-q3-1", "s-peff-q4-1",
"s-peff-q5-1", "s-peff-q6-1", "Raw Income", "Income", "Raw ELL", "ELL", "Raw SpEd", "SpEd", "Progress Count", "Housing Status", "Raw Housing Status", "Home Language", "Home Languages"].to_set.sort "s-peff-q5-1", "s-peff-q6-1", "Raw Income", "Income", "Raw ELL", "ELL", "Raw SpEd", "SpEd", "Progress Count", "Housing Status", "Raw Housing Status", "Home Language", "Home Languages", "Declared Races of Children from Parents"].to_set.sort
end end
def invalid_rows_are_rejected_for_the_correct_reasons(data) def invalid_rows_are_rejected_for_the_correct_reasons(data)

View file

@ -457,6 +457,92 @@ RSpec.describe SurveyItemValues, type: :model do
end end
end end
context ".races_of_children" do
context "when there are no races listed" do
it "returns an unknown race" do
row = {"Race-1" => ""}
row.keys.each do |key|
headers << key
end
values = SurveyItemValues.new(row:, headers:, survey_items:, schools:, academic_years:)
expect(values.races_of_children).to eq [99]
end
end
context "when the only races listed are unknown" do
it "returns an unknown race" do
row = {"Race-1" => "99", "Race-2" => "99", "Race-3" => "", "Race-4" => "nil"}
row.keys.each do |key|
headers << key
end
values = SurveyItemValues.new(row:, headers:, survey_items:, schools:, academic_years:)
expect(values.races_of_children).to eq [99]
end
end
context "when there is one race defined" do
context "for defined races" do
it "returns the qualtrics code of that race" do
[1,2,3,4,5,8].each do |i|
row = {"Race-1" => "#{i}"}
row.keys.each do |key|
headers << key
end
values = SurveyItemValues.new(row:, headers:, survey_items:, schools:, academic_years:)
expect(values.races_of_children).to eq [i]
end
end
end
context "when the qualtrics code need to be translated" do
it "returns 99 (unknown) for 'prefer not to disclose' or prefer to self describe" do
row = {"Race-1" => "6"}
row.keys.each do |key|
headers << key
end
values = SurveyItemValues.new(row:, headers:, survey_items:, schools:, academic_years:)
expect(values.races_of_children).to eq [99]
row = {"Race-1" => "7"}
row.keys.each do |key|
headers << key
end
values = SurveyItemValues.new(row:, headers:, survey_items:, schools:, academic_years:)
expect(values.races_of_children).to eq [99]
end
end
end
context "when there is more than one race defined" do
it "returns the qualtrics code for the two races and the designation for multiracial(100)" do
row = {"Race-1" => "1", "Race-2" => "2","Race-3" => "3"}
row.keys.each do |key|
headers << key
end
values = SurveyItemValues.new(row:, headers:, survey_items:, schools:, academic_years:)
expect(values.races_of_children).to eq [1,2,3,100]
end
end
end
context ".respondent_type" do context ".respondent_type" do
it "reads header to find the survey type" do it "reads header to find the survey type" do
headers = %w[s-sbel-q5 s-phys-q2 RecordedDate] headers = %w[s-sbel-q5 s-phys-q2 RecordedDate]

View file

@ -120,14 +120,14 @@ describe SurveyResponsesDataLoader do
let(:not_ell) { create(:ell, designation: "Not ELL") } let(:not_ell) { create(:ell, designation: "Not ELL") }
let(:unknown_ell) { create(:ell, designation: "Unknown") } let(:unknown_ell) { create(:ell, designation: "Unknown") }
let(:american_indian) { create(:race, qualtrics_code: 1) } let(:american_indian) { create(:race, qualtrics_code: 1, designation: "American Indian or Alaskan Native") }
let(:asian) { create(:race, qualtrics_code: 2) } let(:asian) { create(:race, qualtrics_code: 2, designation: "Asian or Pacific Islander") }
let(:black) { create(:race, qualtrics_code: 3) } let(:black) { create(:race, qualtrics_code: 3, designation: "Black or African American") }
let(:latinx) { create(:race, qualtrics_code: 4) } let(:latinx) { create(:race, qualtrics_code: 4, designation: "Hispanic or Latinx") }
let(:white) { create(:race, qualtrics_code: 5) } let(:white) { create(:race, qualtrics_code: 5, designation: "White or Caucasian") }
let(:middle_eastern) { create(:race, qualtrics_code: 8) } let(:middle_eastern) { create(:race, qualtrics_code: 8, designation: "Middle Eastern") }
let(:unknown_race) { create(:race, qualtrics_code: 99) } let(:unknown_race) { create(:race, qualtrics_code: 99, designation: "Race/Ethnicity Not Listed") }
let(:multiracial) { create(:race, qualtrics_code: 100) } let(:multiracial) { create(:race, qualtrics_code: 100, designation: "Multiracial") }
let(:languages){ let(:languages){
create(:language, designation: "English") create(:language, designation: "English")
@ -265,7 +265,7 @@ describe SurveyResponsesDataLoader do
survey_item: SurveyItem.parent_survey_items).count).to eq 23 survey_item: SurveyItem.parent_survey_items).count).to eq 23
end end
expect(SurveyItemResponse.where(response_id: "parent_survey_response_7").count).to eq 0 expect(SurveyItemResponse.where(response_id: "parent_survey_response_8").count).to eq 0
end end
it "does not add surveyitems from questions that have been disabled" do it "does not add surveyitems from questions that have been disabled" do
@ -273,6 +273,10 @@ describe SurveyResponsesDataLoader do
expect(SurveyItemResponse.where(school:, survey_item: id).count).to eq 0 expect(SurveyItemResponse.where(school:, survey_item: id).count).to eq 0
end end
end end
it "loads the correct set of races for parents" do
assigns_races_to_parents
end
end end
end end
@ -465,3 +469,23 @@ def assigns_races_to_students
expect(race).to eq value expect(race).to eq value
end end
end end
def assigns_races_to_parents
results = {
"parent_survey_response_1" => [american_indian],
"parent_survey_response_2" => [unknown_race],
"parent_survey_response_3" => [american_indian, latinx, white, multiracial],
"parent_survey_response_4" => [unknown_race],
"parent_survey_response_5" => [american_indian, asian, black, latinx, white, middle_eastern,
multiracial],
"parent_survey_response_6" => [american_indian, asian, black, latinx, white, middle_eastern,
multiracial],
"parent_survey_response_7" => [white] }
results.each do |key, value|
race = SurveyItemResponse.find_by_response_id(key).parent.races.to_a
qualtrics = race.map(&:qualtrics_code).sort
expect(race).to eq value
end
end