diff --git a/app/models/housing.rb b/app/models/housing.rb
index a5dbe10d..b930a547 100644
--- a/app/models/housing.rb
+++ b/app/models/housing.rb
@@ -1,4 +1,7 @@
class Housing < ApplicationRecord
+ has_many :parents, dependent: :nullify
+ scope :by_designation, -> { all.map { |housing| [housing.designation, housing] }.to_h }
+
def self.to_designation(housing)
return "Unknown" if housing.blank?
diff --git a/app/models/language.rb b/app/models/language.rb
new file mode 100644
index 00000000..71f5e992
--- /dev/null
+++ b/app/models/language.rb
@@ -0,0 +1,33 @@
+class Language < ApplicationRecord
+ scope :by_designation, -> { all.map { |language| [language.designation, language] }.to_h }
+ has_many :parent_languages, dependent: :destroy
+ has_many :parents, through: :parent_languages, dependent: :nullify
+
+ include FriendlyId
+
+ friendly_id :designation, use: [:slugged]
+ def self.to_designation(language)
+ return "Prefer not to disclose" if language.blank?
+
+ case language
+ in /^1$/i
+ "English"
+ in /^2$/i
+ "Portuguese"
+ in /^3$/i
+ "Spanish"
+ in /^99$/i
+ "Prefer not to disclose"
+ in /|^100$/i
+ "Prefer to self-describe"
+ else
+ puts "************************************"
+ puts "******** ERROR **********"
+ puts ""
+ puts "Error parsing Language column. '#{language}' is not a known value. Halting execution"
+ puts ""
+ puts "************************************"
+ exit
+ end
+ end
+end
diff --git a/app/models/measure.rb b/app/models/measure.rb
index 72a794b4..67c7e9fa 100644
--- a/app/models/measure.rb
+++ b/app/models/measure.rb
@@ -51,6 +51,10 @@ class Measure < ActiveRecord::Base
@student_scales ||= scales.student_scales
end
+ def parent_scales
+ @parent_scales ||= scales.parent_scales
+ end
+
def includes_teacher_survey_items?
@includes_teacher_survey_items ||= teacher_survey_items.length.positive?
end
diff --git a/app/models/parent.rb b/app/models/parent.rb
index 2d556d15..ea815ac8 100644
--- a/app/models/parent.rb
+++ b/app/models/parent.rb
@@ -1,2 +1,5 @@
class Parent < ApplicationRecord
+ belongs_to :housing, optional: true
+ has_many :parent_languages
+ has_and_belongs_to_many :languages, join_table: :parent_languages
end
diff --git a/app/models/parent_language.rb b/app/models/parent_language.rb
new file mode 100644
index 00000000..ec878727
--- /dev/null
+++ b/app/models/parent_language.rb
@@ -0,0 +1,4 @@
+class ParentLanguage < ApplicationRecord
+ belongs_to :parent
+ belongs_to :language
+end
diff --git a/app/models/report/measure_summary.rb b/app/models/report/measure_summary.rb
index ae8099d7..b9b64242 100644
--- a/app/models/report/measure_summary.rb
+++ b/app/models/report/measure_summary.rb
@@ -21,15 +21,11 @@ module Report
Thread.new do
while measure = jobs.pop(true)
academic_years.each do |academic_year|
- all_grades = Set.new
-
respondents = Respondent.where(school: schools, academic_year:)
- respondents.each do |respondent|
- respondent.enrollment_by_grade.keys.each do |grade|
- all_grades.add(grade)
- end
- end
- all_grades = all_grades.to_a
+
+ enrollment = respondents.map do | respondent| respondent.enrollment_by_grade.keys end.flatten.compact.uniq.sort
+ grades_with_responses = ::SurveyItemResponse.where(school: schools, academic_year:).where.not(grade: nil).pluck(:grade).uniq.sort
+ all_grades = (enrollment & grades_with_responses).sort
grades = "#{all_grades.first}-#{all_grades.last}"
begin_date = ::SurveyItemResponse.where(school: schools,
diff --git a/app/models/sped.rb b/app/models/sped.rb
index eaca0437..b132aeb9 100644
--- a/app/models/sped.rb
+++ b/app/models/sped.rb
@@ -10,9 +10,9 @@ class Sped < ApplicationRecord
case sped
in /active|^A$|1|^Special\s*Education$/i
"Special Education"
- in %r{^I$|exited|0|^Not\s*Special\s*Education$|Does\s*not\s*apply|Referred|Ineligible|^No\s*special\s*needs$|Not\s*SPED|^#*N/*A$}i
+ in /^I$|exited|0|^Not\s*Special\s*Education$|Does\s*not\s*apply|Referred|Ineligible|^No\s*special\s*needs$|Not\s*SPED/i
"Not Special Education"
- in /^Unknown|^SpecialEdStatus|^SPED/i
+ in %r{^#*N/*A$|^Unknown|^SpecialEdStatus|^SPED}i
"Unknown"
else
puts "************************************"
diff --git a/app/models/survey_item_response.rb b/app/models/survey_item_response.rb
index ed559983..5c93dbcb 100644
--- a/app/models/survey_item_response.rb
+++ b/app/models/survey_item_response.rb
@@ -51,6 +51,10 @@ class SurveyItemResponse < ActiveRecord::Base
).where("student_races.race_id": race.id).group(:survey_item).having("count(*) >= 10").average(:likert_score)
}
+ 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)
+ }
+
def self.grouped_responses(school:, academic_year:)
@grouped_responses ||= Hash.new do |memo, (school, academic_year)|
memo[[school, academic_year]] =
diff --git a/app/presenters/analyze/graph/column/language.rb b/app/presenters/analyze/graph/column/language.rb
new file mode 100644
index 00000000..68d6915d
--- /dev/null
+++ b/app/presenters/analyze/graph/column/language.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+module Analyze
+ module Graph
+ module Column
+ class Language < ColumnBase
+ attr_reader :language, :label
+
+ def initialize(languages:, label:)
+ @language = languages
+ @label = label
+ end
+
+ def basis
+ "parent surveys"
+ end
+
+ def show_irrelevancy_message?(measure:)
+ false
+ end
+
+ def show_insufficient_data_message?(measure:, school:, academic_years:)
+ false
+ end
+
+ def type
+ :parent
+ end
+
+ def n_size(measure:, school:, academic_year:)
+ SurveyItemResponse.joins([parent: :languages]).where(languages: { designation: designations }, survey_item: measure.parent_survey_items, school:, academic_year:).select(:parent_id).distinct.count
+ end
+
+ def score(measure:, school:, academic_year:)
+ return Score::NIL_SCORE if n_size(measure:, school:, academic_year:) < 10
+
+ averages = SurveyItemResponse.averages_for_language(measure.parent_survey_items, school, academic_year,
+ designations)
+ average = bubble_up_averages(measure:, averages:).round(2)
+ Score.new(average:,
+ meets_teacher_threshold: false,
+ meets_student_threshold: true,
+ meets_admin_data_threshold: false)
+ end
+
+ def designations
+ language.map(&:designation)
+ end
+
+ def bubble_up_averages(measure:, averages:)
+ measure.parent_scales.map do |scale|
+ scale.survey_items.map do |survey_item|
+ averages[survey_item]
+ end.remove_blanks.average
+ end.remove_blanks.average
+ end
+ end
+ end
+ end
+end
diff --git a/app/presenters/analyze/graph/parents_by_language.rb b/app/presenters/analyze/graph/parents_by_language.rb
new file mode 100644
index 00000000..06079db8
--- /dev/null
+++ b/app/presenters/analyze/graph/parents_by_language.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+module Analyze
+ module Graph
+ class ParentsByLanguage
+ attr_reader :speds
+
+ ALL_LANGUAGES = Language.all
+ ENGLISH_LANGUAGES = ALL_LANGUAGES.select { |language| language.designation == "English" }
+ UNKNOWN_LANGUAGES = ALL_LANGUAGES.select { |language| language.designation == "Prefer not to disclose" }
+ NON_ENGLISH_LANGUAGES = (ALL_LANGUAGES - ENGLISH_LANGUAGES - UNKNOWN_LANGUAGES)
+
+ def to_s
+ "Parents by Language"
+ end
+
+ def slug
+ "parents-by-language"
+ end
+
+ def columns
+ [].tap do |array|
+ array << Analyze::Graph::Column::Language.new(languages: ENGLISH_LANGUAGES, label: ["English", "Speaking"])
+ array << Analyze::Graph::Column::Language.new(languages: NON_ENGLISH_LANGUAGES, label: ["Non English", "Speaking"])
+ array << Analyze::Graph::Column::Language.new(languages: UNKNOWN_LANGUAGES, label: ["Unknown"])
+ array << Analyze::Graph::Column::Language.new(languages: ALL_LANGUAGES, label: ["All", "Parents"])
+ 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: "Language", slug: "language", graph: self)
+ end
+ end
+ end
+end
diff --git a/app/presenters/analyze/presenter.rb b/app/presenters/analyze/presenter.rb
index d3dde077..50e27b92 100644
--- a/app/presenters/analyze/presenter.rb
+++ b/app/presenters/analyze/presenter.rb
@@ -96,10 +96,14 @@ module Analyze
end
def groups
- @groups = graphs.map(&:group)
- .reject { |group| group.name.nil? }
- .sort_by { |group| group.name }
- .uniq
+ @groups ||=
+ begin
+ first_char_of_class_name = graph.class.name.demodulize.first
+ graphs.select { |graph| graph.class.name.demodulize.first == first_char_of_class_name }.map(&:group)
+ .reject { |group| group.name.nil? }
+ .sort_by { |group| group.name }
+ .uniq
+ end
end
def group
@@ -159,7 +163,8 @@ module Analyze
Analyze::Graph::StudentsByGender.new(genders: selected_genders),
Analyze::Graph::StudentsByIncome.new(incomes: selected_incomes),
Analyze::Graph::StudentsBySped.new(speds: selected_speds),
- Analyze::Graph::StudentsByEll.new(ells: selected_ells)]
+ Analyze::Graph::StudentsByEll.new(ells: selected_ells),
+ Analyze::Graph::ParentsByLanguage.new]
end
def graph
diff --git a/app/presenters/analyze/slice/parents_by_group.rb b/app/presenters/analyze/slice/parents_by_group.rb
new file mode 100644
index 00000000..f97d93f7
--- /dev/null
+++ b/app/presenters/analyze/slice/parents_by_group.rb
@@ -0,0 +1,9 @@
+module Analyze
+ module Slice
+ class ParentsByGroup < Base
+ def initialize(graph:, label: "Parents by Group", slug: "parents-by-group")
+ super(label:, slug:, graph:)
+ end
+ end
+ end
+end
diff --git a/app/services/cleaner.rb b/app/services/cleaner.rb
index a190a37a..6463340b 100644
--- a/app/services/cleaner.rb
+++ b/app/services/cleaner.rb
@@ -79,7 +79,7 @@ class Cleaner
headers = headers.to_set
headers = headers.merge(Set.new(["Raw Income", "Income", "Raw ELL", "ELL", "Raw SpEd", "SpEd", "Progress Count",
- "Race", "Gender", "Raw Housing Status", "Housing Status"])).to_a
+ "Race", "Gender", "Raw Housing Status", "Housing Status", "Home Language", "Home Languages"])).to_a
filtered_headers = include_all_headers(headers:)
filtered_headers = remove_unwanted_headers(headers: filtered_headers)
log_headers = (filtered_headers + ["Valid Duration?", "Valid Progress?", "Valid Grade?",
diff --git a/app/services/demographic_loader.rb b/app/services/demographic_loader.rb
index 36170251..5c2aa3ce 100644
--- a/app/services/demographic_loader.rb
+++ b/app/services/demographic_loader.rb
@@ -9,6 +9,7 @@ class DemographicLoader
create_from_column(column: "ELL", row:, model: Ell)
create_from_column(column: "Special Ed Status", row:, model: Sped)
create_from_column(column: "Housing", row:, model: Housing)
+ create_from_column(column: "Language", row:, model: Language)
end
end
diff --git a/app/services/survey_item_values.rb b/app/services/survey_item_values.rb
index e619bb62..0e739883 100644
--- a/app/services/survey_item_values.rb
+++ b/app/services/survey_item_values.rb
@@ -22,6 +22,7 @@ class SurveyItemValues
row["Gender"] ||= gender
row["Raw Housing Status"] = raw_housing
row["Housing Status"] = housing
+ row["Home Languages"] = languages.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)
@@ -161,7 +162,7 @@ class SurveyItemValues
# Only check the secondary hispanic column if we don't have self reported data and are relying on SIS data
if self_report.nil? && sis.present?
hispanic = value_from(pattern: /Hispanic\s*Latino/i)&.downcase
- race_codes = race_codes.reject { |code| code == 5 } if hispanic == "true" && race_codes.count == 1
+ race_codes = race_codes.reject { |code| code == 5 } if ["true", "1"].include?(hispanic) || race_codes.count == 1
race_codes = race_codes.push(4) if %w[true 1].include?(hispanic)
end
@@ -170,7 +171,7 @@ class SurveyItemValues
end
def lasid
- @lasid ||= value_from(pattern: /LASID/i)
+ @lasid ||= value_from(pattern: /LASID/i) || ""
end
def raw_income
@@ -205,6 +206,20 @@ class SurveyItemValues
@housing ||= Housing.to_designation(raw_housing)
end
+ def raw_language
+ @raw_language ||= value_from(pattern: /^Language$/i) || ""
+ end
+
+ def languages
+ @languages ||= [].tap do |languages|
+ if raw_language.present?
+ raw_language.split(",").each do |item|
+ languages << Language.to_designation(item)
+ end
+ end
+ end
+ end
+
def number_of_children
@number_of_children ||= value_from(pattern: /Number\s*Of\s*Children/i).to_i
end
@@ -219,6 +234,9 @@ class SurveyItemValues
output ||= row[match]&.strip
end
+ output = output.delete("\u0000") if output.present?
+ output = output.delete("\x00") if output.present?
+ output.encode!('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '') if output.present?
output
end
diff --git a/app/services/survey_responses_data_loader.rb b/app/services/survey_responses_data_loader.rb
index 6da9ef71..ea303679 100644
--- a/app/services/survey_responses_data_loader.rb
+++ b/app/services/survey_responses_data_loader.rb
@@ -86,19 +86,31 @@ class SurveyResponsesDataLoader
process_survey_items(row:)
end
+ def languages
+ @languages ||= Language.by_designation
+ end
+
+ def housings
+ @housings ||= Housing.by_designation
+ end
+
def process_survey_items(row:)
student = nil
parent = nil
if row.respondent_type == :student
student = Student.find_or_create_by(response_id: row.response_id, lasid: row.lasid)
student.races.delete_all
- tmp_races = row.races.map { |race| races[race] }
+ tmp_races = row.races.map { |race| races[race] }.reject(&:nil?)
student.races += tmp_races
end
if row.respondent_type == :parent
parent = Parent.find_or_create_by(response_id: row.response_id)
parent.number_of_children = row.number_of_children
+ tmp_languages = row.languages.map { |language| languages[language] }.reject(&:nil?)
+ parent.languages.delete_all
+ parent.languages.concat(tmp_languages)
+ parent.housing = housings[row.housing] if row.housing.present?
parent.save
end
diff --git a/app/views/analyze/_data_filters.html.erb b/app/views/analyze/_data_filters.html.erb
index f1eecfa4..a1698a36 100644
--- a/app/views/analyze/_data_filters.html.erb
+++ b/app/views/analyze/_data_filters.html.erb
@@ -1,32 +1,8 @@
- <% @presenter.sources.each do |source| %>
-
-<%= form_with(url: district_school_analyze_index_path,
- method: :get,
- data: {
- turbo_frame: "results",
- turbo_action: "advance",
- controller: "analyze",
- action: "input->analyze#submit"
- }) do |f| %>
-
- <% params.reject{|key,_| key == "graph"}.each do |key, value| %>
-
- <% end %>
-
>
-
-
- <% end %>
-
-
-<% if source.slug != "all-data" %>
+<% @presenter.sources.each do |source| %>
+ <%# Source options; e.g. 'All Data' or 'Survey Data only' %>
<%= form_with(url: district_school_analyze_index_path,
method: :get,
data: {
@@ -36,28 +12,52 @@
action: "input->analyze#submit"
}) do |f| %>
- <% params.reject{|key,_| key == "graph"}.each do |key, value| %>
-
- <% end %>
+ <% params.reject{|key,_| key == "graph"}.each do |key, value| %>
+
+ <% end %>
- <% @presenter.slices.each do | slice | %>
-
- <%= slice.slug == "all-data" ? "hidden" : "" %>>
-
-
-
+ id="<%= source.slug %>"
+ class="form-check-input"
+ name="graph"
+ value="<%= source.graph.slug %>"
+ <%= source.slug == @presenter.source.slug ? "checked" : "" %>>
+
+ <% end %>
+
+
+ <% if source.slug != "all-data" %>
+ <%= form_with(url: district_school_analyze_index_path,
+ method: :get,
+ data: {
+ turbo_frame: "results",
+ turbo_action: "advance",
+ controller: "analyze",
+ action: "input->analyze#submit"
+ }) do |f| %>
+
+ <% params.reject{|key,_| key == "graph"}.each do |key, value| %>
+
+ <% end %>
+
+ <% @presenter.slices.each do | slice | %>
+
+
+ <%= slice.slug == "all-data" ? "hidden" : "" %>>
+
+
+
+ <% end %>
<% end %>
- <% end %>
<% end %>
<% end %>
- <%= render partial: "group_selectors" %>
+<%= render partial: "group_selectors" %>
diff --git a/data/demographics.csv b/data/demographics.csv
index e2a005aa..9823c81c 100644
--- a/data/demographics.csv
+++ b/data/demographics.csv
@@ -1,11 +1,11 @@
-Race Qualtrics Code,Race/Ethnicity,Gender Qualtrics Code,Sex/Gender,Income,ELL,Special Ed Status,Housing
-1,American Indian or Alaskan Native,2,Male,Economically Disadvantaged - N,ELL,Special Education,Own
-2,Asian or Pacific Islander,1,Female,Economically Disadvantaged - Y,Not ELL,Not Special Education,Rent
-3,Black or African American,4,Non-Binary,Unknown,Unknown,Unknown,Unknown
-4,Hispanic or Latinx,99,Unknown,,,,
-5,White or Caucasian,,,,,,
-6,Prefer not to disclose,,,,,,
-7,Prefer to self-describe,,,,,,
-8,Middle Eastern,,,,,,
-99,Race/Ethnicity Not Listed,,,,,,
-100,Multiracial,,,,,,
+Race Qualtrics Code,Race/Ethnicity,Gender Qualtrics Code,Sex/Gender,Income,ELL,Special Ed Status,Housing,Language
+1,American Indian or Alaskan Native,2,Male,Economically Disadvantaged - N,ELL,Special Education,Own,English
+2,Asian or Pacific Islander,1,Female,Economically Disadvantaged - Y,Not ELL,Not Special Education,Rent,Portuguese
+3,Black or African American,4,Non-Binary,Unknown,Unknown,Unknown,Unknown,Spanish
+4,Hispanic or Latinx,99,Unknown,,,,,Prefer not to disclose
+5,White or Caucasian,,,,,,,Prefer to self-describe
+6,Prefer not to disclose,,,,,,,
+7,Prefer to self-describe,,,,,,,
+8,Middle Eastern,,,,,,,
+99,Race/Ethnicity Not Listed,,,,,,,
+100,Multiracial,,,,,,,
diff --git a/db/migrate/20250408212201_add_housing_to_parent.rb b/db/migrate/20250408212201_add_housing_to_parent.rb
new file mode 100644
index 00000000..ed297cf3
--- /dev/null
+++ b/db/migrate/20250408212201_add_housing_to_parent.rb
@@ -0,0 +1,5 @@
+class AddHousingToParent < ActiveRecord::Migration[8.0]
+ def change
+ add_reference :parents, :housing, foreign_key: true
+ end
+end
diff --git a/db/migrate/20250411213850_create_languages.rb b/db/migrate/20250411213850_create_languages.rb
new file mode 100644
index 00000000..65021c7f
--- /dev/null
+++ b/db/migrate/20250411213850_create_languages.rb
@@ -0,0 +1,10 @@
+class CreateLanguages < ActiveRecord::Migration[8.0]
+ def change
+ create_table :languages do |t|
+ t.string :designation
+ t.string :slug
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20250418184427_create_parent_languages.rb b/db/migrate/20250418184427_create_parent_languages.rb
new file mode 100644
index 00000000..1cae5fc1
--- /dev/null
+++ b/db/migrate/20250418184427_create_parent_languages.rb
@@ -0,0 +1,12 @@
+class CreateParentLanguages < ActiveRecord::Migration[8.0]
+ def change
+ create_table :parent_languages do |t|
+ t.references :parent, null: false, foreign_key: true
+ t.references :language, null: false, foreign_key: true
+
+ t.timestamps
+ end
+
+ add_index :parent_languages, %i[parent_id language_id]
+ end
+end
diff --git a/db/migrate/20250418185032_add_designation_index_to_language.rb b/db/migrate/20250418185032_add_designation_index_to_language.rb
new file mode 100644
index 00000000..221b98bf
--- /dev/null
+++ b/db/migrate/20250418185032_add_designation_index_to_language.rb
@@ -0,0 +1,5 @@
+class AddDesignationIndexToLanguage < ActiveRecord::Migration[8.0]
+ def change
+ add_index :languages, %i[designation]
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index f16565ab..9e62ba38 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[8.0].define(version: 2025_03_27_205800) do
+ActiveRecord::Schema[8.0].define(version: 2025_04_18_185655) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_catalog.plpgsql"
@@ -102,6 +102,14 @@ ActiveRecord::Schema[8.0].define(version: 2025_03_27_205800) do
t.index ["slug"], name: "index_incomes_on_slug", unique: true
end
+ create_table "languages", force: :cascade do |t|
+ t.string "designation"
+ t.string "slug"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["designation"], name: "index_languages_on_designation"
+ end
+
create_table "legacy_attempts", id: :serial, force: :cascade do |t|
t.integer "recipient_id"
t.integer "schedule_id"
@@ -322,11 +330,23 @@ ActiveRecord::Schema[8.0].define(version: 2025_03_27_205800) do
t.index ["subcategory_id"], name: "index_measures_on_subcategory_id"
end
+ create_table "parent_languages", force: :cascade do |t|
+ t.bigint "parent_id", null: false
+ t.bigint "language_id", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["language_id"], name: "index_parent_languages_on_language_id"
+ t.index ["parent_id", "language_id"], name: "index_parent_languages_on_parent_id_and_language_id"
+ t.index ["parent_id"], name: "index_parent_languages_on_parent_id"
+ end
+
create_table "parents", force: :cascade do |t|
t.string "response_id"
t.integer "number_of_children"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
+ t.bigint "housing_id"
+ t.index ["housing_id"], name: "index_parents_on_housing_id"
end
create_table "races", force: :cascade do |t|
@@ -514,6 +534,9 @@ ActiveRecord::Schema[8.0].define(version: 2025_03_27_205800) do
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 "measures", "subcategories"
+ add_foreign_key "parent_languages", "languages"
+ add_foreign_key "parent_languages", "parents"
+ add_foreign_key "parents", "housings"
add_foreign_key "respondents", "academic_years"
add_foreign_key "respondents", "schools"
add_foreign_key "response_rates", "academic_years"
diff --git a/spec/factories.rb b/spec/factories.rb
index e9aa534b..81f184bf 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -1,4 +1,13 @@
FactoryBot.define do
+ factory :parent_language do
+ parent { nil }
+ language { nil }
+ end
+
+ factory :language do
+ designation { "MyString" }
+ end
+
factory :housing do
designation { "MyString" }
end
diff --git a/spec/fixtures/demographic_glossary.csv b/spec/fixtures/demographic_glossary.csv
index 4ff277d8..ca8bfcb1 100644
--- a/spec/fixtures/demographic_glossary.csv
+++ b/spec/fixtures/demographic_glossary.csv
@@ -1,21 +1,24 @@
-ELL Value,ELL Type,ELL Headers,Sped Value,Sped Type,Sped Headers,Income Value,Income Type,Income Headers
-EL student not 1st year,ELL,EL Student First Year,A,Special Education,Special Ed Status,Free Lunch,Economically Disadvantaged – Y,Low Income
-"EL student, not 1st year",ELL,Raw ELL,active,Special Education,Raw SPED,Reduced Lunch,Economically Disadvantaged – Y,Raw Income
-EL student 1st year,ELL,ELL- SIS,1,Special Education,SPED- SIS,LowIncome,Economically Disadvantaged – Y,SES- SIS
-"EL student, 1st year",ELL,DirectCert,Special Education,Special Education,SPED,Low Income,Economically Disadvantaged – Y,EconDisadvantaged
-EL - Early Child. or PK,ELL,ELL,Referred,Not Special Education,,Reduced price lunch,Economically Disadvantaged – Y,Income SIS
-1,ELL,English Learner,Ineligible,Not Special Education,,TRUE,Economically Disadvantaged – Y,SES
-lep student 1st year,ELL,,I,Not Special Education,,1,Economically Disadvantaged – Y,DirectCert
-lep student not 1st year,ELL,,exited,Not Special Education,,Not Eligible,Economically Disadvantaged – N,
-LEP Not1stYr,ELL,,0,Not Special Education,,FALSE,Economically Disadvantaged – N,
-LEP1stYr US Sch,ELL,,Not Special Education,Not Special Education,,0,Economically Disadvantaged – N,
-Does not apply,Not ELL,,Does not apply,Not Special Education,,[blanks],Economically Disadvantaged – N,
-0,Not ELL,,[blanks],Not Special Education,,#NA,Unknown,
-2,Not ELL,,#NA,Unknown,,NA,Unknown,
-3,Not ELL,,NA,Unknown,,N/A,Unknown,
-[blanks],Not ELL,,N/A,Unknown,,#N/A,Unknown,
-#NA,Unknown,,#N/A,Unknown,,Income,Unknown,
-NA,Unknown,,SPED,Unknown,,Yes,Economically Disadvantaged – Y,
-N/A,Unknown,,No special needs,Not Special Education,,No,Economically Disadvantaged – N,
-#N/A,Unknown,,,,,,,
-ELL,ELL,,,,,,,
+ELL Value,ELL Type,ELL Headers,Sped Value,Sped Type,Sped Headers,Income Value,Income Type,Income Headers,Language Value,Language Type
+EL student not 1st year,ELL,EL Student First Year,A,Special Education,Special Ed Status,Free Lunch,Economically Disadvantaged – Y,Low Income,1,English
+"EL student, not 1st year",ELL,Raw ELL,active,Special Education,Raw SPED,Reduced Lunch,Economically Disadvantaged – Y,Raw Income,2,Portuguese
+EL student 1st year,ELL,ELL- SIS,1,Special Education,SPED- SIS,LowIncome,Economically Disadvantaged – Y,SES- SIS,3,Spanish
+"EL student, 1st year",ELL,DirectCert,Special Education,Special Education,SPED,Low Income,Economically Disadvantaged – Y,EconDisadvantaged,99,Prefer not to disclose
+EL - Early Child. or PK,ELL,ELL,Referred,Not Special Education,,Reduced price lunch,Economically Disadvantaged – Y,Income SIS,100,Prefer to self-describe
+1,ELL,English Learner,Ineligible,Not Special Education,,TRUE,Economically Disadvantaged – Y,SES ,,
+lep student 1st year,ELL,ELL Status- SIS,I,Not Special Education,,1,Economically Disadvantaged – Y,DirectCert,,
+lep student not 1st year,ELL,,exited,Not Special Education,,Not Eligible,Economically Disadvantaged – N,,,
+LEP Not1stYr,ELL,,0,Not Special Education,,FALSE,Economically Disadvantaged – N,,,
+LEP1stYr US Sch,ELL,,Not Special Education,Not Special Education,,0,Economically Disadvantaged – N,,,
+Does not apply,Not ELL,,Does not apply,Not Special Education,,[blanks],Economically Disadvantaged – N,,,
+0,Not ELL,,[blanks],Unknown,,#NA,Unknown,,,
+2,Not ELL,,#NA,Unknown,,NA,Unknown,,,
+3,Not ELL,,NA,Unknown,,N/A,Unknown,,,
+[blanks],Not ELL,,N/A,Unknown,,#N/A,Unknown,,,
+#NA,Unknown,,#N/A,Unknown,,Income,Unknown,,,
+NA,Unknown,,SPED,Unknown,,Yes,Economically Disadvantaged – Y,,,
+N/A,Unknown,,No special needs,Not Special Education,,No,Economically Disadvantaged – N,,,
+#N/A,Unknown,,Not SPED,Not Special Education,,,,,,
+ELL,ELL,,,,,,,,,
+LEP Not 1st Year,ELL,,,,,,,,,
+Yes,ELL,,,,,,,,,
+No,Not ELL,,,,,,,,,
diff --git a/spec/models/language_spec.rb b/spec/models/language_spec.rb
new file mode 100644
index 00000000..924d9ca5
--- /dev/null
+++ b/spec/models/language_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe Language, type: :model do
+ pending "add some examples to (or delete) #{__FILE__}"
+end
diff --git a/spec/models/parent_language_spec.rb b/spec/models/parent_language_spec.rb
new file mode 100644
index 00000000..720c6862
--- /dev/null
+++ b/spec/models/parent_language_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe ParentLanguage, type: :model do
+ pending "add some examples to (or delete) #{__FILE__}"
+end
diff --git a/spec/presenters/analyze/presenter_spec.rb b/spec/presenters/analyze/presenter_spec.rb
index bba430b3..675dfb98 100644
--- a/spec/presenters/analyze/presenter_spec.rb
+++ b/spec/presenters/analyze/presenter_spec.rb
@@ -366,38 +366,37 @@ describe Analyze::Presenter do
context ".group" do
context "when no parameters are provided" do
- it "returns the first item in the list of groups" do
- params = {}
- presenter = Analyze::Presenter.new(params:, school:, academic_year:)
- expect(presenter.group.slug).to eq presenter.groups.first.slug
+ it "returns no groups when no params are defined" do
+ presenter = Analyze::Presenter.new(params: {}, school:, academic_year:)
+ expect(presenter.groups).to eq []
end
end
context "when a group is provided in the params hash" do
it "returns the group with the given slug" do
- params = { group: "gender" }
+ params = { group: "gender", graph: "students-by-gender" }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.group.slug).to eq "gender"
- params = { group: "grade" }
+ params = { group: "grade", graph: "students-by-grade" }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.group.slug).to eq "grade"
- params = { group: "race" }
+ params = { group: "race", graph: "students-by-race" }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.group.slug).to eq "race"
- params = { group: "income" }
+ params = { group: "income", graph: "students-by-income" }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
expect(presenter.group.slug).to eq "income"
end
end
context "when a parameter that does not match a group is provided" do
- it "returns the first item in the list of groups" do
- params = { group: "invalid group" }
+ it "returns nil when invalid parameters are given" do
+ params = { group: "invalid group", graph: "invalid graph" }
presenter = Analyze::Presenter.new(params:, school:, academic_year:)
- expect(presenter.group.slug).to eq presenter.groups.first.slug
+ expect(presenter.group).to eq nil
end
end
end
diff --git a/spec/services/cleaner_spec.rb b/spec/services/cleaner_spec.rb
index 4733f7d6..6b7a137c 100644
--- a/spec/services/cleaner_spec.rb
+++ b/spec/services/cleaner_spec.rb
@@ -301,6 +301,7 @@ end
def reads_headers_from_raw_csv(processed_data)
processed_data in [headers, clean_csv, log_csv, data]
+
expect(headers.to_set.sort).to eq ["StartDate", "EndDate", "Status", "IPAddress", "Progress", "Duration (in seconds)",
"Finished", "RecordedDate", "ResponseId", "District", "School",
"LASID", "Gender", "Race", "What grade are you in?", "s-tint-q1",
@@ -314,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-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-peff-q5-1", "s-peff-q6-1", "Raw Income", "Income", "Raw ELL", "ELL", "Raw SpEd", "SpEd", "Progress Count", "Housing Status", "Raw Housing Status"].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"].to_set.sort
end
def invalid_rows_are_rejected_for_the_correct_reasons(data)
diff --git a/spec/services/survey_item_values_spec.rb b/spec/services/survey_item_values_spec.rb
index e884d645..ac60e8c3 100644
--- a/spec/services/survey_item_values_spec.rb
+++ b/spec/services/survey_item_values_spec.rb
@@ -414,7 +414,7 @@ RSpec.describe SurveyItemValues, type: :model do
end
context "when there are multiple races" do
- it "returns the gender that maps to the gender provided" do
+ it "returns the race that maps to the race provided" do
row = { "Race" => "1,2,3" }
values = SurveyItemValues.new(row:, headers:, survey_items:, schools:, academic_years:)
expect(values.races).to eq [1, 2, 3, 100]
@@ -452,7 +452,7 @@ RSpec.describe SurveyItemValues, type: :model do
headers.push("HispanicLatino")
headers.push("Race- SIS")
values = SurveyItemValues.new(row:, headers:, survey_items:, schools:, academic_years:)
- expect(values.races).to eq [5, 2, 3, 4, 100]
+ expect(values.races).to eq [2, 3, 4, 100]
end
end
end
@@ -567,6 +567,22 @@ RSpec.describe SurveyItemValues, type: :model do
# end
end
+ context ".language" do
+ before :each do
+ attleboro
+ ay_2022_23
+ end
+
+ it "validates the code matches the expectations defined in the demographic_glossary" do
+
+ list = read(demographic_filepath, "Language Value", "Language Type")
+
+ list.each do |target, result|
+ compare("Language", target, [result], :languages)
+ end
+ end
+ end
+
context ".ell" do
before :each do
attleboro
diff --git a/spec/services/survey_responses_data_loader_spec.rb b/spec/services/survey_responses_data_loader_spec.rb
index 2f2cf747..7212882e 100644
--- a/spec/services/survey_responses_data_loader_spec.rb
+++ b/spec/services/survey_responses_data_loader_spec.rb
@@ -91,6 +91,12 @@ describe SurveyResponsesDataLoader do
]
end
+ let(:housings) do
+ create(:housing, designation: "Own")
+ create(:housing, designation: "Rent")
+ create(:housing, designation: "Unknown")
+ end
+
let(:t_pcom_q3) { create(:survey_item, survey_item_id: "t-pcom-q3") }
let(:t_pcom_q2) { create(:survey_item, survey_item_id: "t-pcom-q2") }
let(:t_coll_q1) { create(:survey_item, survey_item_id: "t-coll-q1") }
@@ -123,12 +129,20 @@ describe SurveyResponsesDataLoader do
let(:unknown_race) { create(:race, qualtrics_code: 99) }
let(:multiracial) { create(:race, qualtrics_code: 100) }
+ let(:languages){
+ create(:language, designation: "English")
+ create(:language, designation: "Spanish")
+ create(:language, designation: "Portuguese")
+ create(:language, designation: "Unknown")
+ }
+
let(:setup) do
ay_2020_21
ay_2022_23
school
second_school
butler_school
+ housings
t_pcom_q3
t_pcom_q2
t_coll_q1
@@ -161,6 +175,8 @@ describe SurveyResponsesDataLoader do
middle_eastern
unknown_race
multiracial
+
+ languages
end
before :each do