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 @@

Data Filters

- <% @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