From 794f07ac380b9f319c59a8d4a586033e36a2ad63 Mon Sep 17 00:00:00 2001 From: Stefanni Brasil Date: Thu, 18 Jun 2026 14:02:37 -0600 Subject: [PATCH 1/8] bundle update rails --- Gemfile | 2 +- Gemfile.lock | 135 ++++++++++++++++++++++++++------------------------- 2 files changed, 70 insertions(+), 67 deletions(-) diff --git a/Gemfile b/Gemfile index 8cef6a7763..69f9803716 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ source "https://rubygems.org" ruby "4.0.3" -gem "rails", "~> 8.0" +gem "rails", "~> 8.1" gem "after_party" # Post-deployment tasks gem "amazing_print" # Easier console reading diff --git a/Gemfile.lock b/Gemfile.lock index 401c299d19..a8113e6be8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,29 +1,31 @@ GEM remote: https://rubygems.org/ specs: - actioncable (8.0.5) - actionpack (= 8.0.5) - activesupport (= 8.0.5) + action_text-trix (2.1.19) + railties + actioncable (8.1.3) + actionpack (= 8.1.3) + activesupport (= 8.1.3) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (8.0.5) - actionpack (= 8.0.5) - activejob (= 8.0.5) - activerecord (= 8.0.5) - activestorage (= 8.0.5) - activesupport (= 8.0.5) + actionmailbox (8.1.3) + actionpack (= 8.1.3) + activejob (= 8.1.3) + activerecord (= 8.1.3) + activestorage (= 8.1.3) + activesupport (= 8.1.3) mail (>= 2.8.0) - actionmailer (8.0.5) - actionpack (= 8.0.5) - actionview (= 8.0.5) - activejob (= 8.0.5) - activesupport (= 8.0.5) + actionmailer (8.1.3) + actionpack (= 8.1.3) + actionview (= 8.1.3) + activejob (= 8.1.3) + activesupport (= 8.1.3) mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (8.0.5) - actionview (= 8.0.5) - activesupport (= 8.0.5) + actionpack (8.1.3) + actionview (= 8.1.3) + activesupport (= 8.1.3) nokogiri (>= 1.8.5) rack (>= 2.2.4) rack-session (>= 1.0.1) @@ -31,46 +33,47 @@ GEM rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) useragent (~> 0.16) - actiontext (8.0.5) - actionpack (= 8.0.5) - activerecord (= 8.0.5) - activestorage (= 8.0.5) - activesupport (= 8.0.5) + actiontext (8.1.3) + action_text-trix (~> 2.1.15) + actionpack (= 8.1.3) + activerecord (= 8.1.3) + activestorage (= 8.1.3) + activesupport (= 8.1.3) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (8.0.5) - activesupport (= 8.0.5) + actionview (8.1.3) + activesupport (= 8.1.3) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - activejob (8.0.5) - activesupport (= 8.0.5) + activejob (8.1.3) + activesupport (= 8.1.3) globalid (>= 0.3.6) - activemodel (8.0.5) - activesupport (= 8.0.5) + activemodel (8.1.3) + activesupport (= 8.1.3) activemodel-serializers-xml (1.0.3) activemodel (>= 5.0.0.a) activesupport (>= 5.0.0.a) builder (~> 3.1) - activerecord (8.0.5) - activemodel (= 8.0.5) - activesupport (= 8.0.5) + activerecord (8.1.3) + activemodel (= 8.1.3) + activesupport (= 8.1.3) timeout (>= 0.4.0) - activestorage (8.0.5) - actionpack (= 8.0.5) - activejob (= 8.0.5) - activerecord (= 8.0.5) - activesupport (= 8.0.5) + activestorage (8.1.3) + actionpack (= 8.1.3) + activejob (= 8.1.3) + activerecord (= 8.1.3) + activesupport (= 8.1.3) marcel (~> 1.0) - activesupport (8.0.5) + activesupport (8.1.3) base64 - benchmark (>= 0.3) bigdecimal concurrent-ruby (~> 1.0, >= 1.3.1) connection_pool (>= 2.2.5) drb i18n (>= 1.6, < 2) + json logger (>= 1.4.2) minitest (>= 5.1) securerandom (>= 0.3) @@ -143,7 +146,7 @@ GEM logger (~> 1.5) cliver (0.3.2) coderay (1.1.3) - concurrent-ruby (1.3.6) + concurrent-ruby (1.3.7) connection_pool (3.0.2) crack (1.0.1) bigdecimal @@ -276,7 +279,7 @@ GEM csv mini_mime (>= 1.0.0) multi_xml (>= 0.5.2) - i18n (1.14.8) + i18n (1.15.1) concurrent-ruby (~> 1.0) image_processing (1.14.0) mini_magick (>= 4.9.5, < 6) @@ -321,7 +324,7 @@ GEM net-imap net-pop net-smtp - marcel (1.1.0) + marcel (1.2.1) matrix (0.4.3) mcp (0.9.2) json-schema (>= 4.1) @@ -349,14 +352,14 @@ GEM net-smtp (0.5.1) net-protocol nio4r (2.7.5) - nokogiri (1.19.3) + nokogiri (1.19.4) mini_portile2 (~> 2.8.2) racc (~> 1.4) - nokogiri (1.19.3-arm64-darwin) + nokogiri (1.19.4-arm64-darwin) racc (~> 1.4) - nokogiri (1.19.3-x86_64-darwin) + nokogiri (1.19.4-x86_64-darwin) racc (~> 1.4) - nokogiri (1.19.3-x86_64-linux-gnu) + nokogiri (1.19.4-x86_64-linux-gnu) racc (~> 1.4) noticed (2.9.3) rails (>= 6.1.0) @@ -457,20 +460,20 @@ GEM rack (>= 1.3) rackup (2.3.1) rack (>= 3) - rails (8.0.5) - actioncable (= 8.0.5) - actionmailbox (= 8.0.5) - actionmailer (= 8.0.5) - actionpack (= 8.0.5) - actiontext (= 8.0.5) - actionview (= 8.0.5) - activejob (= 8.0.5) - activemodel (= 8.0.5) - activerecord (= 8.0.5) - activestorage (= 8.0.5) - activesupport (= 8.0.5) + rails (8.1.3) + actioncable (= 8.1.3) + actionmailbox (= 8.1.3) + actionmailer (= 8.1.3) + actionpack (= 8.1.3) + actiontext (= 8.1.3) + actionview (= 8.1.3) + activejob (= 8.1.3) + activemodel (= 8.1.3) + activerecord (= 8.1.3) + activestorage (= 8.1.3) + activesupport (= 8.1.3) bundler (>= 1.15.0) - railties (= 8.0.5) + railties (= 8.1.3) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1) @@ -482,9 +485,9 @@ GEM rails-html-sanitizer (1.7.0) loofah (~> 2.25) nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) - railties (8.0.5) - actionpack (= 8.0.5) - activesupport (= 8.0.5) + railties (8.1.3) + actionpack (= 8.1.3) + activesupport (= 8.1.3) irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) @@ -535,9 +538,9 @@ GEM json-schema (>= 2.2, < 7.0) railties (>= 5.2, < 8.2) rspec-core (>= 2.14) - rswag-ui (2.16.0) - actionpack (>= 5.2, < 8.1) - railties (>= 5.2, < 8.1) + rswag-ui (2.17.0) + actionpack (>= 5.2, < 8.2) + railties (>= 5.2, < 8.2) rubocop (1.84.2) json (~> 2.3) language_server-protocol (~> 3.17.0.2) @@ -684,7 +687,7 @@ GEM crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) websocket (1.2.11) - websocket-driver (0.8.0) + websocket-driver (0.8.1) base64 websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) @@ -761,7 +764,7 @@ DEPENDENCIES pundit rack-attack rack-cors - rails (~> 8.0) + rails (~> 8.1) rails-controller-testing request_store rexml From e89507224d4014cddbaf5b676f27ba8380f0f428 Mon Sep 17 00:00:00 2001 From: Stefanni Brasil Date: Thu, 18 Jun 2026 14:11:52 -0600 Subject: [PATCH 2/8] reviewed files we want to keep --- bin/bundler-audit | 6 ++ config/bundler-audit.yml | 5 ++ config/environments/development.rb | 3 + .../initializers/content_security_policy.rb | 4 + config/initializers/inflections.rb | 2 +- .../new_framework_defaults_8_1.rb | 74 +++++++++++++++++++ config/puma.rb | 5 +- public/400.html | 31 ++++++-- public/406-unsupported-browser.html | 29 +++++++- public/422.html | 31 ++++++-- 10 files changed, 173 insertions(+), 17 deletions(-) create mode 100755 bin/bundler-audit create mode 100644 config/bundler-audit.yml create mode 100644 config/initializers/new_framework_defaults_8_1.rb diff --git a/bin/bundler-audit b/bin/bundler-audit new file mode 100755 index 0000000000..e2ef22690c --- /dev/null +++ b/bin/bundler-audit @@ -0,0 +1,6 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "bundler/audit/cli" + +ARGV.concat %w[ --config config/bundler-audit.yml ] if ARGV.empty? || ARGV.include?("check") +Bundler::Audit::CLI.start diff --git a/config/bundler-audit.yml b/config/bundler-audit.yml new file mode 100644 index 0000000000..e74b3af949 --- /dev/null +++ b/config/bundler-audit.yml @@ -0,0 +1,5 @@ +# Audit all gems listed in the Gemfile for known security problems by running bin/bundler-audit. +# CVEs that are not relevant to the application can be enumerated on the ignore list below. + +ignore: + - CVE-THAT-DOES-NOT-APPLY diff --git a/config/environments/development.rb b/config/environments/development.rb index 493e6fc73c..ac7c230e0a 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -77,6 +77,9 @@ config.action_controller.forgery_protection_origin_check = false end + # Uncomment if you wish to allow Action Cable access from any origin. + # config.action_cable.disable_request_forgery_protection = true + # Raise error when a before_action's only/except options reference missing actions. config.action_controller.raise_on_missing_callback_actions = false diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index b3076b38fe..d51d713979 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -20,6 +20,10 @@ # config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } # config.content_security_policy_nonce_directives = %w(script-src style-src) # +# # Automatically add `nonce` to `javascript_tag`, `javascript_include_tag`, and `stylesheet_link_tag` +# # if the corresponding directives are specified in `content_security_policy_nonce_directives`. +# # config.content_security_policy_nonce_auto = true +# # # Report violations without enforcing the policy. # # config.content_security_policy_report_only = true # end diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb index e2fdd60539..0ce5929819 100644 --- a/config/initializers/inflections.rb +++ b/config/initializers/inflections.rb @@ -15,5 +15,5 @@ # inflect.acronym "RESTful" # end ActiveSupport::Inflector.inflections(:en) do |inflect| - inflect.acronym "DSS" # TODO what is this for? + inflect.acronym "DSS" end diff --git a/config/initializers/new_framework_defaults_8_1.rb b/config/initializers/new_framework_defaults_8_1.rb new file mode 100644 index 0000000000..5cc706343c --- /dev/null +++ b/config/initializers/new_framework_defaults_8_1.rb @@ -0,0 +1,74 @@ +# Be sure to restart your server when you modify this file. +# +# This file eases your Rails 8.1 framework defaults upgrade. +# +# Uncomment each configuration one by one to switch to the new default. +# Once your application is ready to run with all new defaults, you can remove +# this file and set the `config.load_defaults` to `8.1`. +# +# Read the Guide for Upgrading Ruby on Rails for more info on each option. +# https://guides.rubyonrails.org/upgrading_ruby_on_rails.html + +### +# Skips escaping HTML entities and line separators. When set to `false`, the +# JSON renderer no longer escapes these to improve performance. +# +# Example: +# class PostsController < ApplicationController +# def index +# render json: { key: "\u2028\u2029<>&" } +# end +# end +# +# Renders `{"key":"\u2028\u2029\u003c\u003e\u0026"}` with the previous default, but `{"key":"

<>&"}` with the config +# set to `false`. +# +# Applications that want to keep the escaping behavior can set the config to `true`. +#++ +Rails.configuration.action_controller.escape_json_responses = false + +### +# Skips escaping LINE SEPARATOR (U+2028) and PARAGRAPH SEPARATOR (U+2029) in JSON. +# +# Historically these characters were not valid inside JavaScript literal strings but that changed in ECMAScript 2019. +# As such it's no longer a concern in modern browsers: https://caniuse.com/mdn-javascript_builtins_json_json_superset. +#++ +Rails.configuration.active_support.escape_js_separators_in_json = false + +### +# Raises an error when order dependent finder methods (e.g. `#first`, `#second`) are called without `order` values +# on the relation, and the model does not have any order columns (`implicit_order_column`, `query_constraints`, or +# `primary_key`) to fall back on. +# +# The current behavior of not raising an error has been deprecated, and this configuration option will be removed in +# Rails 8.2. +#++ +Rails.configuration.active_record.raise_on_missing_required_finder_order_columns = true + +### +# Controls how Rails handles path relative URL redirects. +# When set to `:raise`, Rails will raise an `ActionController::Redirecting::UnsafeRedirectError` +# for relative URLs without a leading slash, which can help prevent open redirect vulnerabilities. +# +# Example: +# redirect_to "example.com" # Raises UnsafeRedirectError +# redirect_to "@attacker.com" # Raises UnsafeRedirectError +# redirect_to "/safe/path" # Works correctly +# +# Applications that want to allow these redirects can set the config to `:log` (previous default) +# to only log warnings, or `:notify` to send ActiveSupport notifications. +#++ +Rails.configuration.action_controller.action_on_path_relative_redirect = :raise + +### +# Use a Ruby parser to track dependencies between Action View templates +#++ +Rails.configuration.action_view.render_tracker = :ruby + +### +# When enabled, hidden inputs generated by `form_tag`, `token_tag`, `method_tag`, and the hidden parameter fields +# included in `button_to` forms will omit the `autocomplete="off"` attribute. +# +# Applications that want to keep generating the `autocomplete` attribute for those tags can set it to `false`. +#++ +Rails.configuration.action_view.remove_hidden_field_autocomplete = true diff --git a/config/puma.rb b/config/puma.rb index a248513b24..38c4b86596 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -7,7 +7,8 @@ # # You can control the number of workers using ENV["WEB_CONCURRENCY"]. You # should only set this value when you want to run 2 or more workers. The -# default is already 1. +# default is already 1. You can set it to `auto` to automatically start a worker +# for each available processor. # # The ideal number of threads per worker depends both on how much time the # application spends waiting for IO operations and on how much you wish to @@ -33,7 +34,7 @@ # Allow puma to be restarted by `bin/rails restart` command. plugin :tmp_restart -# Run the Solid Queue supervisor inside of Puma for single-server deployments +# Run the Solid Queue supervisor inside of Puma for single-server deployments. plugin :solid_queue if ENV["SOLID_QUEUE_IN_PUMA"] # Specify the PID file. Defaults to tmp/pids/server.pid in development. diff --git a/public/400.html b/public/400.html index 282dbc8cc9..640de03397 100644 --- a/public/400.html +++ b/public/400.html @@ -35,12 +35,35 @@ font-weight: 400; letter-spacing: -0.0025em; line-height: 1.4; - min-height: 100vh; + min-height: 100dvh; place-items: center; text-rendering: optimizeLegibility; -webkit-text-size-adjust: 100%; } + #error-description { + fill: #d30001; + } + + #error-id { + fill: #f0eff0; + } + + @media (prefers-color-scheme: dark) { + body { + background: #101010; + color: #e0e0e0; + } + + #error-description { + fill: #FF6161; + } + + #error-id { + fill: #2c2c2c; + } + } + a { color: inherit; font-weight: 700; @@ -83,13 +106,11 @@ } main article br { - display: none; @media(min-width: 48em) { display: inline; } - } @@ -102,10 +123,10 @@
- +
-

The server cannot process the request due to a client error. Please check the request and try again. If you’re the application owner check the logs for more information.

+

The server cannot process the request due to a client error. Please check the request and try again. If you're the application owner check the logs for more information.

diff --git a/public/406-unsupported-browser.html b/public/406-unsupported-browser.html index 9532a9ccd0..43d2811e8c 100644 --- a/public/406-unsupported-browser.html +++ b/public/406-unsupported-browser.html @@ -35,12 +35,35 @@ font-weight: 400; letter-spacing: -0.0025em; line-height: 1.4; - min-height: 100vh; + min-height: 100dvh; place-items: center; text-rendering: optimizeLegibility; -webkit-text-size-adjust: 100%; } + #error-description { + fill: #d30001; + } + + #error-id { + fill: #f0eff0; + } + + @media (prefers-color-scheme: dark) { + body { + background: #101010; + color: #e0e0e0; + } + + #error-description { + fill: #FF6161; + } + + #error-id { + fill: #2c2c2c; + } + } + a { color: inherit; font-weight: 700; @@ -83,13 +106,11 @@ } main article br { - display: none; @media(min-width: 48em) { display: inline; } - } @@ -102,7 +123,7 @@
- +

Your browser is not supported.
Please upgrade your browser to continue.

diff --git a/public/422.html b/public/422.html index 8bcf06014f..f12fb4aa17 100644 --- a/public/422.html +++ b/public/422.html @@ -35,12 +35,35 @@ font-weight: 400; letter-spacing: -0.0025em; line-height: 1.4; - min-height: 100vh; + min-height: 100dvh; place-items: center; text-rendering: optimizeLegibility; -webkit-text-size-adjust: 100%; } + #error-description { + fill: #d30001; + } + + #error-id { + fill: #f0eff0; + } + + @media (prefers-color-scheme: dark) { + body { + background: #101010; + color: #e0e0e0; + } + + #error-description { + fill: #FF6161; + } + + #error-id { + fill: #2c2c2c; + } + } + a { color: inherit; font-weight: 700; @@ -83,13 +106,11 @@ } main article br { - display: none; @media(min-width: 48em) { display: inline; } - } @@ -102,10 +123,10 @@
- +
-

The change you wanted was rejected. Maybe you tried to change something you didn’t have access to. If you’re the application owner check the logs for more information.

+

The change you wanted was rejected. Maybe you tried to change something you didn't have access to. If you're the application owner check the logs for more information.

From 946a7167d36cdaf229f94e5286b6409eec00718e Mon Sep 17 00:00:00 2001 From: Stefanni Brasil Date: Thu, 18 Jun 2026 14:12:08 -0600 Subject: [PATCH 3/8] commit all to view changes in the browser, easier to compare --- config/environments/development.rb | 41 +++++++------------ config/environments/production.rb | 63 +++++++++++++----------------- config/environments/test.rb | 36 +++++------------ 3 files changed, 51 insertions(+), 89 deletions(-) diff --git a/config/environments/development.rb b/config/environments/development.rb index ac7c230e0a..885961f81a 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -20,33 +20,29 @@ if Rails.root.join("tmp/caching-dev.txt").exist? config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true - config.cache_store = :memory_store - config.public_file_server.headers = {"cache-control" => "public, max-age=#{2.days.to_i}"} + config.public_file_server.headers = { "cache-control" => "public, max-age=#{2.days.to_i}" } else config.action_controller.perform_caching = false - config.cache_store = :null_store end + # Change to :null_store to avoid any caching. + config.cache_store = :memory_store + # Store uploaded files on the local file system (see config/storage.yml for options). config.active_storage.service = :local # Don't care if the mailer can't send. - config.action_mailer.default_url_options = {host: "localhost", port: 3000} # Set localhost to be used by links generated in mailer templates. - config.action_mailer.delivery_method = :letter_opener - config.action_mailer.perform_deliveries = true + config.action_mailer.raise_delivery_errors = false + # Make template changes take effect immediately. config.action_mailer.perform_caching = false - config.action_mailer.raise_delivery_errors = false + + # Set localhost to be used by links generated in mailer templates. + config.action_mailer.default_url_options = { host: "localhost", port: 3000 } # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log - # Raise exceptions for disallowed deprecations. - config.active_support.disallowed_deprecation = :raise - - # Tell Active Support which deprecation messages to disallow. - config.active_support.disallowed_deprecation_warnings = [] - # Raise an error on page load if there are pending migrations. config.active_record.migration_error = :page_load @@ -59,29 +55,20 @@ # Highlight code that enqueued background job in logs. config.active_job.verbose_enqueue_logs = true - # Suppress logger output for asset requests. - config.assets.quiet = true - config.assets.digest = false + # Highlight code that triggered redirect in logs. + config.action_dispatch.verbose_redirect_logs = true - # Prosopite N+1 query detection - config.prosopite_enabled = true - config.prosopite_min_n_queries = 5 # More lenient for development + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true # Annotate rendered view with file names. config.action_view.annotate_rendered_view_with_filenames = true - config.hosts << ENV["DEV_HOSTS"] - config.hosts << ".app.github.dev" - - if ENV["CODESPACES"] === "true" - config.action_controller.forgery_protection_origin_check = false - end - # Uncomment if you wish to allow Action Cable access from any origin. # config.action_cable.disable_request_forgery_protection = true # Raise error when a before_action's only/except options reference missing actions. - config.action_controller.raise_on_missing_callback_actions = false + config.action_controller.raise_on_missing_callback_actions = true # Apply autocorrection by RuboCop to files generated by `bin/rails generate`. # config.generators.apply_rubocop_autocorrect_after_generate! diff --git a/config/environments/production.rb b/config/environments/production.rb index 7c310a9f9a..cb0241df64 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -1,25 +1,8 @@ +require "active_support/core_ext/integer/time" + Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. - # Set host to be used by links generated in mailer templates. - config.action_mailer.default_url_options = {host: ENV["DOMAIN"]} - # Ignore bad email addresses and do not raise email delivery errors. - # Set this to true and configure the email server for immediate delivery to raise delivery errors. - config.action_mailer.raise_delivery_errors = true - config.action_mailer.show_previews = ENV["APP_ENVIRONMENT"] != "production" - # Do not send emails in staging or qa - config.action_mailer.perform_deliveries = ENV["APP_ENVIRONMENT"] == "production" - config.action_mailer.delivery_method = :smtp - # Specify outgoing SMTP server. - config.action_mailer.smtp_settings = { - address: "smtp-relay.sendinblue.com", - port: 587, - user_name: ENV["SENDINBLUE_EMAIL"], - password: ENV["SENDINBLUE_PASSWORD"], - authentication: "login", - enable_starttls_auto: true - } - # Code is not reloaded between requests. config.enable_reloading = false @@ -32,30 +15,29 @@ # Turn on fragment caching in view templates. config.action_controller.perform_caching = true - # Ensures that a master key has been made available in ENV["RAILS_MASTER_KEY"], config/master.key, or an environment - # key such as config/credentials/production.key. This key is used to decrypt credentials (and other encrypted files). - config.require_master_key = true - - # Enable static file serving from the `/public` folder (turn off if using NGINX/Apache for it). - config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + # Cache assets for far-future expiry since they are all digest stamped. + config.public_file_server.headers = { "cache-control" => "public, max-age=#{1.year.to_i}" } # Enable serving of images, stylesheets, and JavaScripts from an asset server. # config.asset_host = "http://assets.example.com" # Store uploaded files on the local file system (see config/storage.yml for options). - config.active_storage.service = :microsoft + config.active_storage.service = :local + + # Assume all access to the app is happening through a SSL-terminating reverse proxy. + # config.assume_ssl = true # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. - config.force_ssl = true + # config.force_ssl = true # Skip http-to-https redirect for the default health check endpoint. # config.ssl_options = { redirect: { exclude: ->(request) { request.path == "/up" } } } # Log to STDOUT with the current request id as a default log tag. - config.log_tags = [:request_id] - config.logger = ActiveSupport::TaggedLogging.logger($stdout) + config.log_tags = [ :request_id ] + config.logger = ActiveSupport::TaggedLogging.logger(STDOUT) - # Change to "debug" to log everything (including potentially personally-identifiable information!) + # Change to "debug" to log everything (including potentially personally-identifiable information!). config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info") # Prevent health checks from clogging up the logs. @@ -70,10 +52,21 @@ # Replace the default in-process and non-durable queuing backend for Active Job. # config.active_job.queue_adapter = :resque - # Use a real queuing backend for Active Job (and separate queues per environment). - config.active_job.queue_adapter = :delayed_job + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Set host to be used by links generated in mailer templates. + config.action_mailer.default_url_options = { host: "example.com" } - config.action_mailer.perform_caching = false + # Specify outgoing SMTP server. Remember to add smtp/* credentials via bin/rails credentials:edit. + # config.action_mailer.smtp_settings = { + # user_name: Rails.application.credentials.dig(:smtp, :user_name), + # password: Rails.application.credentials.dig(:smtp, :password), + # address: "smtp.example.com", + # port: 587, + # authentication: :plain + # } # Enable locale fallbacks for I18n (makes lookups for any locale fall back to # the I18n.default_locale when a translation cannot be found). @@ -82,8 +75,8 @@ # Do not dump schema after migrations. config.active_record.dump_schema_after_migration = false - # Inspect all attributes in production. New default is :id. - config.active_record.attributes_for_inspect = [:all] + # Only use :id for inspections in production. + config.active_record.attributes_for_inspect = [ :id ] # Enable DNS rebinding protection and other `Host` header attacks. # config.hosts = [ diff --git a/config/environments/test.rb b/config/environments/test.rb index 1b61cc7031..c2095b1174 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -7,9 +7,7 @@ # Settings specified here will take precedence over those in config/application.rb. # While tests run files are not watched, reloading is not necessary. - config.enable_reloading = ENV["CI"].blank? - - config.action_view.cache_template_loading = true + config.enable_reloading = false # Eager loading loads your entire application. When running a single test locally, # this is usually not necessary, and can slow down your test suite. However, it's @@ -18,15 +16,11 @@ config.eager_load = ENV["CI"].present? # Configure public file server for tests with cache-control for performance. - config.public_file_server.enabled = true - config.public_file_server.headers = { - "Cache-Control" => "public, max-age=#{1.hour.to_i}" - } + config.public_file_server.headers = { "cache-control" => "public, max-age=3600" } # Show full error reports. config.consider_all_requests_local = true - - config.action_controller.perform_caching = false + config.cache_store = :null_store # Render exception templates for rescuable exceptions and raise for other exceptions. config.action_dispatch.show_exceptions = :rescuable @@ -37,35 +31,23 @@ # Store uploaded files on the local file system in a temporary directory. config.active_storage.service = :test - config.action_mailer.perform_caching = false - # Tell Action Mailer not to deliver emails to the real world. # The :test delivery method accumulates sent emails in the # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test # Set host to be used by links generated in mailer templates. - config.action_mailer.default_url_options = {host: "localhost", port: 3000} + config.action_mailer.default_url_options = { host: "example.com" } # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr - # Rack Attack configuration - # Set IP_BLOCKLIST for testing. Can't stub in spec since environment variable - # gets read during application initialization. - ENV["IP_BLOCKLIST"] = "4.5.6.7, 9.8.7.6,100.101.102.103" - - # Raise exceptions for disallowed deprecations. - config.active_support.disallowed_deprecation = :raise - - # Tell Active Support which deprecation messages to disallow. - config.active_support.disallowed_deprecation_warnings = [] - # Raises error for missing translations. - config.i18n.raise_on_missing_translations = true + # config.i18n.raise_on_missing_translations = true - # Raise error when a before_action's only/except options reference missing actions. - config.action_controller.raise_on_missing_callback_actions = false + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true - config.secret_key_base = ENV["SECRET_KEY_BASE"] || "dummy_test_secret_key" + # Raise error when a before_action's only/except options reference missing actions. + config.action_controller.raise_on_missing_callback_actions = true end From 87180a1939f6199e93316de0b8ec44cc8fc19c54 Mon Sep 17 00:00:00 2001 From: Stefanni Brasil Date: Thu, 18 Jun 2026 14:24:54 -0600 Subject: [PATCH 4/8] keep previous config --- config/environments/development.rb | 39 +++++++++++++++++----- config/environments/production.rb | 52 ++++++++++++++++++++---------- config/environments/test.rb | 38 ++++++++++++++++++---- 3 files changed, 97 insertions(+), 32 deletions(-) diff --git a/config/environments/development.rb b/config/environments/development.rb index 885961f81a..d4fc67b336 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -20,29 +20,34 @@ if Rails.root.join("tmp/caching-dev.txt").exist? config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true + config.cache_store = :memory_store config.public_file_server.headers = { "cache-control" => "public, max-age=#{2.days.to_i}" } else config.action_controller.perform_caching = false + config.cache_store = :null_store end - # Change to :null_store to avoid any caching. - config.cache_store = :memory_store - # Store uploaded files on the local file system (see config/storage.yml for options). config.active_storage.service = :local # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false + config.action_mailer.default_url_options = {host: "localhost", port: 3000} # Set localhost to be used by links generated in mailer templates. + config.action_mailer.delivery_method = :letter_opener + config.action_mailer.perform_deliveries = true # Make template changes take effect immediately. config.action_mailer.perform_caching = false - # Set localhost to be used by links generated in mailer templates. - config.action_mailer.default_url_options = { host: "localhost", port: 3000 } - # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + # Raise an error on page load if there are pending migrations. config.active_record.migration_error = :page_load @@ -59,16 +64,34 @@ config.action_dispatch.verbose_redirect_logs = true # Raises error for missing translations. - # config.i18n.raise_on_missing_translations = true + config.i18n.raise_on_missing_translations = true + + # Suppress logger output for asset requests. + config.assets.quiet = true + config.assets.digest = false # Annotate rendered view with file names. config.action_view.annotate_rendered_view_with_filenames = true + # Prosopite N+1 query detection + config.prosopite_enabled = true + config.prosopite_min_n_queries = 5 # More lenient for development + # Uncomment if you wish to allow Action Cable access from any origin. # config.action_cable.disable_request_forgery_protection = true # Raise error when a before_action's only/except options reference missing actions. - config.action_controller.raise_on_missing_callback_actions = true + config.action_controller.raise_on_missing_callback_actions = false + + # Uncomment if you wish to allow Action Cable access from any origin. + # config.action_cable.disable_request_forgery_protection = true + + config.hosts << ENV["DEV_HOSTS"] + config.hosts << ".app.github.dev" + + if ENV["CODESPACES"] === "true" + config.action_controller.forgery_protection_origin_check = false + end # Apply autocorrection by RuboCop to files generated by `bin/rails generate`. # config.generators.apply_rubocop_autocorrect_after_generate! diff --git a/config/environments/production.rb b/config/environments/production.rb index cb0241df64..f5675af94f 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -3,6 +3,25 @@ Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. + # Set host to be used by links generated in mailer templates. + config.action_mailer.default_url_options = {host: ENV["DOMAIN"]} + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + config.action_mailer.raise_delivery_errors = true + config.action_mailer.show_previews = ENV["APP_ENVIRONMENT"] != "production" + # Do not send emails in staging or qa + config.action_mailer.perform_deliveries = ENV["APP_ENVIRONMENT"] == "production" + config.action_mailer.delivery_method = :smtp + # Specify outgoing SMTP server. + config.action_mailer.smtp_settings = { + address: "smtp-relay.sendinblue.com", + port: 587, + user_name: ENV["SENDINBLUE_EMAIL"], + password: ENV["SENDINBLUE_PASSWORD"], + authentication: "login", + enable_starttls_auto: true + } + # Code is not reloaded between requests. config.enable_reloading = false @@ -15,6 +34,13 @@ # Turn on fragment caching in view templates. config.action_controller.perform_caching = true + # Ensures that a master key has been made available in ENV["RAILS_MASTER_KEY"], config/master.key, or an environment + # key such as config/credentials/production.key. This key is used to decrypt credentials (and other encrypted files). + config.require_master_key = true + + # Enable static file serving from the `/public` folder (turn off if using NGINX/Apache for it). + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + # Cache assets for far-future expiry since they are all digest stamped. config.public_file_server.headers = { "cache-control" => "public, max-age=#{1.year.to_i}" } @@ -22,20 +48,20 @@ # config.asset_host = "http://assets.example.com" # Store uploaded files on the local file system (see config/storage.yml for options). - config.active_storage.service = :local + config.active_storage.service = :microsoft # Assume all access to the app is happening through a SSL-terminating reverse proxy. # config.assume_ssl = true # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. - # config.force_ssl = true + config.force_ssl = true # Skip http-to-https redirect for the default health check endpoint. # config.ssl_options = { redirect: { exclude: ->(request) { request.path == "/up" } } } # Log to STDOUT with the current request id as a default log tag. - config.log_tags = [ :request_id ] - config.logger = ActiveSupport::TaggedLogging.logger(STDOUT) + config.log_tags = [:request_id] + config.logger = ActiveSupport::TaggedLogging.logger($stdout) # Change to "debug" to log everything (including potentially personally-identifiable information!). config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info") @@ -56,17 +82,9 @@ # Set this to true and configure the email server for immediate delivery to raise delivery errors. # config.action_mailer.raise_delivery_errors = false - # Set host to be used by links generated in mailer templates. - config.action_mailer.default_url_options = { host: "example.com" } - - # Specify outgoing SMTP server. Remember to add smtp/* credentials via bin/rails credentials:edit. - # config.action_mailer.smtp_settings = { - # user_name: Rails.application.credentials.dig(:smtp, :user_name), - # password: Rails.application.credentials.dig(:smtp, :password), - # address: "smtp.example.com", - # port: 587, - # authentication: :plain - # } + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false # Enable locale fallbacks for I18n (makes lookups for any locale fall back to # the I18n.default_locale when a translation cannot be found). @@ -75,8 +93,8 @@ # Do not dump schema after migrations. config.active_record.dump_schema_after_migration = false - # Only use :id for inspections in production. - config.active_record.attributes_for_inspect = [ :id ] + # Inspect all attributes in production. New default is :id. + config.active_record.attributes_for_inspect = [:all] # Enable DNS rebinding protection and other `Host` header attacks. # config.hosts = [ diff --git a/config/environments/test.rb b/config/environments/test.rb index c2095b1174..ed97c38a6e 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -6,8 +6,8 @@ Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. - # While tests run files are not watched, reloading is not necessary. - config.enable_reloading = false + config.enable_reloading = ENV["CI"].blank? + config.action_view.cache_template_loading = true # Eager loading loads your entire application. When running a single test locally, # this is usually not necessary, and can slow down your test suite. However, it's @@ -16,12 +16,17 @@ config.eager_load = ENV["CI"].present? # Configure public file server for tests with cache-control for performance. - config.public_file_server.headers = { "cache-control" => "public, max-age=3600" } + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } # Show full error reports. config.consider_all_requests_local = true config.cache_store = :null_store + config.action_controller.perform_caching = false + # Render exception templates for rescuable exceptions and raise for other exceptions. config.action_dispatch.show_exceptions = :rescuable @@ -31,23 +36,42 @@ # Store uploaded files on the local file system in a temporary directory. config.active_storage.service = :test + config.action_mailer.perform_caching = false + # Tell Action Mailer not to deliver emails to the real world. # The :test delivery method accumulates sent emails in the # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test # Set host to be used by links generated in mailer templates. - config.action_mailer.default_url_options = { host: "example.com" } + config.action_mailer.default_url_options = {host: "localhost", port: 3000} # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr + # Rack Attack configuration + # Set IP_BLOCKLIST for testing. Can't stub in spec since environment variable + # gets read during application initialization. + ENV["IP_BLOCKLIST"] = "4.5.6.7, 9.8.7.6,100.101.102.103" + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + # Raises error for missing translations. - # config.i18n.raise_on_missing_translations = true + config.i18n.raise_on_missing_translations = true + + # Raise error when a before_action's only/except options reference missing actions. + + config.action_controller.raise_on_missing_callback_actions = true # Annotate rendered view with file names. - # config.action_view.annotate_rendered_view_with_filenames = true + config.action_view.annotate_rendered_view_with_filenames = true # Raise error when a before_action's only/except options reference missing actions. - config.action_controller.raise_on_missing_callback_actions = true + config.action_controller.raise_on_missing_callback_actions = false + + config.secret_key_base = ENV["SECRET_KEY_BASE"] || "dummy_test_secret_key" end From 2f013de69add40d0a676e8494f8b1b9f40110fae Mon Sep 17 00:00:00 2001 From: Stefanni Brasil Date: Thu, 18 Jun 2026 14:28:44 -0600 Subject: [PATCH 5/8] Rails 8: schema update (no functional change, reorder columns alphabetically) --- db/schema.rb | 406 +++++++++++++++++++++++++-------------------------- 1 file changed, 203 insertions(+), 203 deletions(-) diff --git a/db/schema.rb b/db/schema.rb index b7639ab4a6..d7379a7e16 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,38 +10,38 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.0].define(version: 2026_04_14_132818) do +ActiveRecord::Schema[8.1].define(version: 2026_04_14_132818) do # These are extensions that must be enabled in order to support this database enable_extension "pg_catalog.plpgsql" create_table "action_text_rich_texts", force: :cascade do |t| - t.string "name", null: false t.text "body" - t.string "record_type", null: false - t.bigint "record_id", null: false t.datetime "created_at", null: false + t.string "name", null: false + t.bigint "record_id", null: false + t.string "record_type", null: false t.datetime "updated_at", null: false t.index ["record_type", "record_id", "name"], name: "index_action_text_rich_texts_uniqueness", unique: true end create_table "active_storage_attachments", force: :cascade do |t| - t.string "name", null: false - t.string "record_type", null: false - t.bigint "record_id", null: false t.bigint "blob_id", null: false t.datetime "created_at", precision: nil, null: false + t.string "name", null: false + t.bigint "record_id", null: false + t.string "record_type", null: false t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id" t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true end create_table "active_storage_blobs", force: :cascade do |t| - t.string "key", null: false - t.string "filename", null: false - t.string "content_type" - t.text "metadata" t.bigint "byte_size", null: false t.string "checksum" + t.string "content_type" t.datetime "created_at", precision: nil, null: false + t.string "filename", null: false + t.string "key", null: false + t.text "metadata" t.string "service_name", null: false t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true end @@ -54,65 +54,65 @@ create_table "additional_expenses", force: :cascade do |t| t.bigint "case_contact_id", null: false + t.datetime "created_at", null: false t.decimal "other_expense_amount" t.string "other_expenses_describe" - t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["case_contact_id"], name: "index_additional_expenses_on_case_contact_id" end create_table "addresses", force: :cascade do |t| t.string "content" - t.bigint "user_id", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.bigint "user_id", null: false t.index ["user_id"], name: "index_addresses_on_user_id" end create_table "all_casa_admins", force: :cascade do |t| + t.datetime "created_at", null: false t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false - t.string "reset_password_token" - t.datetime "reset_password_sent_at", precision: nil - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.string "invitation_token" - t.datetime "invitation_created_at", precision: nil - t.datetime "invitation_sent_at", precision: nil t.datetime "invitation_accepted_at", precision: nil + t.datetime "invitation_created_at", precision: nil t.integer "invitation_limit" + t.datetime "invitation_sent_at", precision: nil + t.string "invitation_token" t.integer "invited_by_id" t.string "invited_by_type" + t.datetime "reset_password_sent_at", precision: nil + t.string "reset_password_token" + t.datetime "updated_at", null: false t.index ["email"], name: "index_all_casa_admins_on_email", unique: true t.index ["invitation_token"], name: "index_all_casa_admins_on_invitation_token", unique: true t.index ["reset_password_token"], name: "index_all_casa_admins_on_reset_password_token", unique: true end create_table "api_credentials", force: :cascade do |t| - t.bigint "user_id", null: false - t.datetime "token_expires_at", default: -> { "(now() + 'PT7H'::interval)" } - t.datetime "refresh_token_expires_at", default: -> { "(now() + 'P30D'::interval)" } t.string "api_token_digest" - t.string "refresh_token_digest" t.datetime "created_at", null: false + t.string "refresh_token_digest" + t.datetime "refresh_token_expires_at", default: -> { "(now() + 'P30D'::interval)" } + t.datetime "token_expires_at", default: -> { "(now() + 'PT7H'::interval)" } t.datetime "updated_at", null: false + t.bigint "user_id", null: false t.index ["api_token_digest"], name: "index_api_credentials_on_api_token_digest", unique: true, where: "(api_token_digest IS NOT NULL)" t.index ["refresh_token_digest"], name: "index_api_credentials_on_refresh_token_digest", unique: true, where: "(refresh_token_digest IS NOT NULL)" end create_table "banners", force: :cascade do |t| - t.bigint "casa_org_id", null: false - t.bigint "user_id", null: false - t.string "name" t.boolean "active", default: false + t.bigint "casa_org_id", null: false t.datetime "created_at", null: false - t.datetime "updated_at", null: false t.datetime "expires_at" + t.string "name" + t.datetime "updated_at", null: false + t.bigint "user_id", null: false end create_table "casa_case_contact_types", force: :cascade do |t| - t.bigint "contact_type_id", null: false t.bigint "casa_case_id", null: false + t.bigint "contact_type_id", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["casa_case_id"], name: "index_casa_case_contact_types_on_casa_case_id" @@ -121,67 +121,67 @@ create_table "casa_case_emancipation_categories", force: :cascade do |t| t.bigint "casa_case_id", null: false - t.bigint "emancipation_category_id", null: false t.datetime "created_at", null: false + t.bigint "emancipation_category_id", null: false t.datetime "updated_at", null: false t.index ["casa_case_id"], name: "index_casa_case_emancipation_categories_on_casa_case_id" end create_table "casa_case_emancipation_options", force: :cascade do |t| t.bigint "casa_case_id", null: false - t.bigint "emancipation_option_id", null: false t.datetime "created_at", null: false + t.bigint "emancipation_option_id", null: false t.datetime "updated_at", null: false t.index ["casa_case_id", "emancipation_option_id"], name: "index_case_options_on_case_id_and_option_id", unique: true end create_table "casa_cases", force: :cascade do |t| - t.string "case_number", null: false - t.boolean "transition_aged_youth", default: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.bigint "casa_org_id", null: false + t.boolean "active", default: true, null: false t.datetime "birth_month_year_youth", precision: nil + t.bigint "casa_org_id", null: false + t.string "case_number", null: false t.datetime "court_report_due_date", precision: nil - t.boolean "active", default: true, null: false - t.datetime "court_report_submitted_at", precision: nil t.integer "court_report_status", default: 0 - t.string "slug" + t.datetime "court_report_submitted_at", precision: nil + t.datetime "created_at", null: false t.datetime "date_in_care" + t.string "slug" + t.boolean "transition_aged_youth", default: false + t.datetime "updated_at", null: false t.index ["casa_org_id"], name: "index_casa_cases_on_casa_org_id" t.index ["case_number", "casa_org_id"], name: "index_casa_cases_on_case_number_and_casa_org_id", unique: true t.index ["slug"], name: "index_casa_cases_on_slug" end create_table "casa_orgs", force: :cascade do |t| - t.string "name", null: false + t.boolean "additional_expenses_enabled", default: false + t.string "address" t.datetime "created_at", null: false - t.datetime "updated_at", null: false t.string "display_name" - t.string "address" t.string "footer_links", default: [], array: true - t.string "slug" + t.boolean "learning_topic_active", default: false + t.string "name", null: false + t.boolean "other_duties_enabled", default: true t.boolean "show_driving_reimbursement", default: true t.boolean "show_fund_request", default: false - t.string "twilio_phone_number" + t.string "slug" t.string "twilio_account_sid" - t.string "twilio_api_key_sid" t.string "twilio_api_key_secret" + t.string "twilio_api_key_sid" t.boolean "twilio_enabled", default: false - t.boolean "additional_expenses_enabled", default: false - t.boolean "learning_topic_active", default: false - t.boolean "other_duties_enabled", default: true + t.string "twilio_phone_number" + t.datetime "updated_at", null: false t.index ["slug"], name: "index_casa_orgs_on_slug", unique: true end create_table "case_assignments", force: :cascade do |t| - t.bigint "casa_case_id", null: false - t.bigint "volunteer_id", null: false t.boolean "active", default: true, null: false + t.boolean "allow_reimbursement", default: true + t.bigint "casa_case_id", null: false t.datetime "created_at", null: false - t.datetime "updated_at", null: false t.boolean "hide_old_contacts", default: false - t.boolean "allow_reimbursement", default: true + t.datetime "updated_at", null: false + t.bigint "volunteer_id", null: false t.index ["casa_case_id"], name: "index_case_assignments_on_casa_case_id" t.index ["volunteer_id"], name: "index_case_assignments_on_volunteer_id" end @@ -196,23 +196,23 @@ end create_table "case_contacts", force: :cascade do |t| - t.bigint "creator_id", null: false t.bigint "casa_case_id" - t.integer "duration_minutes" - t.datetime "occurred_at", precision: nil - t.datetime "created_at", null: false - t.datetime "updated_at", null: false t.boolean "contact_made", default: false + t.datetime "created_at", null: false + t.bigint "creator_id", null: false + t.datetime "deleted_at", precision: nil + t.integer "draft_case_ids", default: [], array: true + t.integer "duration_minutes" t.string "medium_type" + t.jsonb "metadata", default: {} t.integer "miles_driven", default: 0, null: false - t.boolean "want_driving_reimbursement", default: false t.string "notes" - t.datetime "deleted_at", precision: nil + t.datetime "occurred_at", precision: nil t.boolean "reimbursement_complete", default: false t.string "status", default: "started" - t.integer "draft_case_ids", default: [], array: true + t.datetime "updated_at", null: false t.string "volunteer_address" - t.jsonb "metadata", default: {} + t.boolean "want_driving_reimbursement", default: false t.index ["casa_case_id"], name: "index_case_contacts_on_casa_case_id" t.index ["creator_id"], name: "index_case_contacts_on_creator_id" t.check_constraint "miles_driven IS NOT NULL OR NOT want_driving_reimbursement", name: "want_driving_reimbursement_only_when_miles_driven" @@ -220,381 +220,381 @@ create_table "case_court_orders", force: :cascade do |t| t.bigint "casa_case_id", null: false + t.bigint "court_date_id" t.datetime "created_at", null: false - t.datetime "updated_at", null: false t.integer "implementation_status" - t.bigint "court_date_id" t.string "text" + t.datetime "updated_at", null: false t.index ["casa_case_id"], name: "index_case_court_orders_on_casa_case_id" t.index ["court_date_id"], name: "index_case_court_orders_on_court_date_id" end create_table "case_group_memberships", force: :cascade do |t| - t.bigint "case_group_id", null: false t.bigint "casa_case_id", null: false + t.bigint "case_group_id", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "case_groups", force: :cascade do |t| t.bigint "casa_org_id", null: false - t.string "name" t.datetime "created_at", null: false + t.string "name" t.datetime "updated_at", null: false end create_table "checklist_items", force: :cascade do |t| - t.integer "hearing_type_id" - t.text "description", null: false t.string "category", null: false - t.boolean "mandatory", default: false, null: false t.datetime "created_at", null: false + t.text "description", null: false + t.integer "hearing_type_id" + t.boolean "mandatory", default: false, null: false t.datetime "updated_at", null: false end create_table "contact_topic_answers", force: :cascade do |t| - t.text "value" t.bigint "case_contact_id", null: false t.bigint "contact_topic_id" - t.boolean "selected", default: false, null: false t.datetime "created_at", null: false - t.datetime "updated_at", null: false t.datetime "deleted_at" + t.boolean "selected", default: false, null: false + t.datetime "updated_at", null: false + t.text "value" t.index ["case_contact_id"], name: "index_contact_topic_answers_on_case_contact_id" end create_table "contact_topics", force: :cascade do |t| - t.bigint "casa_org_id", null: false t.boolean "active", default: true, null: false - t.boolean "soft_delete", default: false, null: false + t.bigint "casa_org_id", null: false + t.datetime "created_at", null: false t.text "details" + t.boolean "exclude_from_court_report", default: false, null: false t.string "question" - t.datetime "created_at", null: false + t.boolean "soft_delete", default: false, null: false t.datetime "updated_at", null: false - t.boolean "exclude_from_court_report", default: false, null: false end create_table "contact_type_groups", force: :cascade do |t| + t.boolean "active", default: true t.bigint "casa_org_id", null: false - t.string "name", null: false t.datetime "created_at", null: false + t.string "name", null: false t.datetime "updated_at", null: false - t.boolean "active", default: true end create_table "contact_types", force: :cascade do |t| + t.boolean "active", default: true t.bigint "contact_type_group_id", null: false - t.string "name", null: false t.datetime "created_at", null: false + t.string "name", null: false t.datetime "updated_at", null: false - t.boolean "active", default: true t.index ["contact_type_group_id"], name: "index_contact_types_on_contact_type_group_id" end create_table "court_dates", force: :cascade do |t| - t.datetime "date", precision: nil, null: false t.bigint "casa_case_id", null: false + t.datetime "court_report_due_date", precision: nil t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "date", precision: nil, null: false t.bigint "hearing_type_id" t.bigint "judge_id" - t.datetime "court_report_due_date", precision: nil + t.datetime "updated_at", null: false t.index ["casa_case_id"], name: "index_court_dates_on_casa_case_id" end create_table "custom_org_links", force: :cascade do |t| - t.bigint "casa_org_id", null: false - t.string "text", null: false - t.string "url", null: false t.boolean "active", default: true, null: false + t.bigint "casa_org_id", null: false t.datetime "created_at", null: false + t.string "text", null: false t.datetime "updated_at", null: false + t.string "url", null: false t.index ["casa_org_id"], name: "index_custom_org_links_on_casa_org_id" end create_table "delayed_jobs", force: :cascade do |t| - t.integer "priority", default: 0, null: false t.integer "attempts", default: 0, null: false + t.datetime "created_at" + t.datetime "failed_at", precision: nil t.text "handler", null: false t.text "last_error" - t.datetime "run_at", precision: nil t.datetime "locked_at", precision: nil - t.datetime "failed_at", precision: nil t.string "locked_by" + t.integer "priority", default: 0, null: false t.string "queue" - t.datetime "created_at" + t.datetime "run_at", precision: nil t.datetime "updated_at" end create_table "emancipation_categories", force: :cascade do |t| - t.string "name", null: false - t.boolean "mutually_exclusive", null: false t.datetime "created_at", null: false + t.boolean "mutually_exclusive", null: false + t.string "name", null: false t.datetime "updated_at", null: false t.index ["name"], name: "index_emancipation_categories_on_name", unique: true end create_table "emancipation_options", force: :cascade do |t| + t.datetime "created_at", null: false t.bigint "emancipation_category_id", null: false t.string "name", null: false - t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["emancipation_category_id", "name"], name: "index_emancipation_options_on_emancipation_category_id_and_name", unique: true end create_table "flipper_features", force: :cascade do |t| - t.string "key", null: false t.datetime "created_at", null: false + t.string "key", null: false t.datetime "updated_at", null: false t.index ["key"], name: "index_flipper_features_on_key", unique: true end create_table "flipper_gates", force: :cascade do |t| + t.datetime "created_at", null: false t.string "feature_key", null: false t.string "key", null: false - t.text "value" - t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.text "value" t.index ["feature_key", "key", "value"], name: "index_flipper_gates_on_feature_key_and_key_and_value", unique: true end create_table "followups", force: :cascade do |t| t.bigint "case_contact_id" - t.bigint "creator_id" - t.integer "status", default: 0 t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.text "note" + t.bigint "creator_id" t.bigint "followupable_id" t.string "followupable_type" + t.text "note" + t.integer "status", default: 0 + t.datetime "updated_at", null: false t.index ["case_contact_id"], name: "index_followups_on_case_contact_id" end create_table "fund_requests", force: :cascade do |t| - t.text "submitter_email" - t.text "youth_name" - t.text "payment_amount" t.text "deadline" - t.text "request_purpose" + t.text "extra_information" + t.text "impact" + t.text "other_funding_source_sought" t.text "payee_name" + t.text "payment_amount" + t.text "request_purpose" t.text "requested_by_and_relationship" - t.text "other_funding_source_sought" - t.text "impact" - t.text "extra_information" + t.text "submitter_email" t.text "timestamps" + t.text "youth_name" end create_table "healths", force: :cascade do |t| + t.datetime "created_at", null: false t.datetime "latest_deploy_time", precision: nil t.integer "singleton_guard" - t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["singleton_guard"], name: "index_healths_on_singleton_guard", unique: true end create_table "hearing_types", force: :cascade do |t| - t.bigint "casa_org_id", null: false - t.string "name", null: false t.boolean "active", default: true, null: false + t.bigint "casa_org_id", null: false t.string "checklist_updated_date", default: "None", null: false + t.string "name", null: false end create_table "judges", force: :cascade do |t| + t.boolean "active", default: true t.bigint "casa_org_id", null: false t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.boolean "active", default: true t.string "name" + t.datetime "updated_at", null: false end create_table "languages", force: :cascade do |t| - t.string "name" t.bigint "casa_org_id", null: false t.datetime "created_at", null: false + t.string "name" t.datetime "updated_at", null: false end create_table "learning_hour_topics", force: :cascade do |t| - t.string "name", null: false t.bigint "casa_org_id", null: false - t.integer "position", default: 1 t.datetime "created_at", null: false + t.string "name", null: false + t.integer "position", default: 1 t.datetime "updated_at", null: false end create_table "learning_hour_types", force: :cascade do |t| + t.boolean "active", default: true t.bigint "casa_org_id", null: false + t.datetime "created_at", null: false t.string "name" - t.boolean "active", default: true t.integer "position", default: 1 - t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "learning_hours", force: :cascade do |t| - t.bigint "user_id", null: false - t.string "name", null: false - t.integer "duration_minutes", null: false + t.datetime "created_at", null: false t.integer "duration_hours", null: false + t.integer "duration_minutes", null: false + t.bigint "learning_hour_topic_id" + t.bigint "learning_hour_type_id" + t.string "name", null: false t.datetime "occurred_at", precision: nil, null: false - t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.bigint "learning_hour_type_id" - t.bigint "learning_hour_topic_id" + t.bigint "user_id", null: false t.index ["user_id"], name: "index_learning_hours_on_user_id" end create_table "login_activities", force: :cascade do |t| - t.string "scope" - t.string "strategy" - t.string "identity" - t.boolean "success" - t.string "failure_reason" - t.string "user_type" - t.bigint "user_id" - t.string "context" - t.string "ip" - t.text "user_agent" - t.text "referrer" t.string "city" - t.string "region" + t.string "context" t.string "country" + t.datetime "created_at" + t.string "failure_reason" + t.string "identity" + t.string "ip" t.float "latitude" t.float "longitude" - t.datetime "created_at" + t.text "referrer" + t.string "region" + t.string "scope" + t.string "strategy" + t.boolean "success" + t.text "user_agent" + t.bigint "user_id" + t.string "user_type" end create_table "mileage_rates", force: :cascade do |t| t.decimal "amount" + t.bigint "casa_org_id", null: false + t.datetime "created_at", null: false t.date "effective_date" t.boolean "is_active", default: true - t.bigint "user_id" - t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.bigint "casa_org_id", null: false + t.bigint "user_id" end create_table "notes", force: :cascade do |t| t.string "content" + t.datetime "created_at", null: false t.bigint "creator_id" - t.string "notable_type" t.bigint "notable_id" - t.datetime "created_at", null: false + t.string "notable_type" t.datetime "updated_at", null: false end create_table "noticed_events", force: :cascade do |t| - t.string "type" - t.string "record_type" - t.bigint "record_id" - t.jsonb "params" t.datetime "created_at", null: false - t.datetime "updated_at", null: false t.integer "notifications_count" + t.jsonb "params" + t.bigint "record_id" + t.string "record_type" + t.string "type" + t.datetime "updated_at", null: false end create_table "noticed_notifications", force: :cascade do |t| - t.string "type" + t.datetime "created_at", null: false t.bigint "event_id", null: false - t.string "recipient_type", null: false - t.bigint "recipient_id", null: false t.datetime "read_at", precision: nil + t.bigint "recipient_id", null: false + t.string "recipient_type", null: false t.datetime "seen_at", precision: nil - t.datetime "created_at", null: false + t.string "type" t.datetime "updated_at", null: false t.index ["recipient_type", "recipient_id"], name: "index_noticed_notifications_on_recipient" end create_table "notifications", force: :cascade do |t| - t.string "recipient_type", null: false - t.bigint "recipient_id", null: false - t.string "type", null: false + t.datetime "created_at", null: false t.jsonb "params" t.datetime "read_at", precision: nil - t.datetime "created_at", null: false + t.bigint "recipient_id", null: false + t.string "recipient_type", null: false + t.string "type", null: false t.datetime "updated_at", null: false end create_table "other_duties", force: :cascade do |t| + t.datetime "created_at", null: false t.bigint "creator_id", null: false t.string "creator_type" - t.datetime "occurred_at", precision: nil t.bigint "duration_minutes" t.text "notes" - t.datetime "created_at", null: false + t.datetime "occurred_at", precision: nil t.datetime "updated_at", null: false end create_table "patch_note_groups", force: :cascade do |t| - t.string "value", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.string "value", null: false t.index ["value"], name: "index_patch_note_groups_on_value", unique: true end create_table "patch_note_types", force: :cascade do |t| - t.string "name", null: false t.datetime "created_at", null: false + t.string "name", null: false t.datetime "updated_at", null: false t.index ["name"], name: "index_patch_note_types_on_name", unique: true end create_table "patch_notes", force: :cascade do |t| + t.datetime "created_at", null: false t.text "note", null: false - t.bigint "patch_note_type_id", null: false t.bigint "patch_note_group_id", null: false - t.datetime "created_at", null: false + t.bigint "patch_note_type_id", null: false t.datetime "updated_at", null: false end create_table "placement_types", force: :cascade do |t| - t.string "name", null: false t.bigint "casa_org_id", null: false t.datetime "created_at", null: false + t.string "name", null: false t.datetime "updated_at", null: false end create_table "placements", force: :cascade do |t| + t.bigint "casa_case_id", null: false + t.datetime "created_at", null: false + t.bigint "creator_id", null: false t.datetime "placement_started_at", null: false t.bigint "placement_type_id", null: false - t.bigint "creator_id", null: false - t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.bigint "casa_case_id", null: false end create_table "preference_sets", force: :cascade do |t| - t.bigint "user_id" t.jsonb "case_volunteer_columns", default: "{}", null: false t.datetime "created_at", null: false - t.datetime "updated_at", null: false t.jsonb "table_state", default: {} + t.datetime "updated_at", null: false + t.bigint "user_id" t.index ["user_id"], name: "index_preference_sets_on_user_id" end create_table "sent_emails", force: :cascade do |t| - t.bigint "user_id" t.bigint "casa_org_id", null: false - t.string "mailer_type" t.string "category" - t.string "sent_address" t.datetime "created_at", null: false + t.string "mailer_type" + t.string "sent_address" t.datetime "updated_at", null: false + t.bigint "user_id" end create_table "sms_notification_events", force: :cascade do |t| - t.string "name" - t.string "user_type" t.datetime "created_at", null: false + t.string "name" t.datetime "updated_at", null: false + t.string "user_type" end create_table "supervisor_volunteers", force: :cascade do |t| - t.bigint "supervisor_id", null: false - t.bigint "volunteer_id", null: false t.datetime "created_at", null: false - t.datetime "updated_at", null: false t.boolean "is_active", default: true + t.bigint "supervisor_id", null: false + t.datetime "updated_at", null: false + t.bigint "volunteer_id", null: false t.index ["supervisor_id"], name: "index_supervisor_volunteers_on_supervisor_id" t.index ["volunteer_id"], name: "index_supervisor_volunteers_on_volunteer_id" end @@ -604,64 +604,64 @@ end create_table "user_languages", force: :cascade do |t| - t.bigint "user_id" - t.bigint "language_id" t.datetime "created_at", null: false + t.bigint "language_id" t.datetime "updated_at", null: false + t.bigint "user_id" t.index ["language_id", "user_id"], name: "index_user_languages_on_language_id_and_user_id", unique: true end create_table "user_reminder_times", force: :cascade do |t| - t.bigint "user_id", null: false t.datetime "case_contact_types" - t.datetime "no_contact_made" t.datetime "created_at", null: false + t.datetime "no_contact_made" t.datetime "updated_at", null: false + t.bigint "user_id", null: false t.index ["user_id"], name: "index_user_reminder_times_on_user_id" end create_table "user_sms_notification_events", force: :cascade do |t| - t.bigint "user_id", null: false - t.bigint "sms_notification_event_id", null: false t.datetime "created_at", null: false + t.bigint "sms_notification_event_id", null: false t.datetime "updated_at", null: false + t.bigint "user_id", null: false end create_table "users", force: :cascade do |t| - t.string "email", default: "", null: false - t.string "encrypted_password", default: "", null: false - t.string "reset_password_token" - t.datetime "reset_password_sent_at", precision: nil - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.boolean "active", default: true t.bigint "casa_org_id", null: false + t.datetime "confirmation_sent_at" + t.string "confirmation_token" + t.datetime "confirmed_at" + t.datetime "created_at", null: false + t.datetime "current_sign_in_at", precision: nil + t.string "current_sign_in_ip" + t.datetime "date_of_birth" t.string "display_name", default: "", null: false - t.string "invitation_token" - t.datetime "invitation_created_at", precision: nil - t.datetime "invitation_sent_at", precision: nil + t.string "email", default: "", null: false + t.string "encrypted_password", default: "", null: false t.datetime "invitation_accepted_at", precision: nil + t.datetime "invitation_created_at", precision: nil t.integer "invitation_limit" - t.string "invited_by_type" - t.bigint "invited_by_id" + t.datetime "invitation_sent_at", precision: nil + t.string "invitation_token" t.integer "invitations_count", default: 0 - t.string "type" - t.boolean "active", default: true - t.integer "sign_in_count", default: 0, null: false - t.datetime "current_sign_in_at", precision: nil + t.bigint "invited_by_id" + t.string "invited_by_type" t.datetime "last_sign_in_at", precision: nil - t.string "current_sign_in_ip" t.string "last_sign_in_ip" + t.boolean "monthly_learning_hours_report", default: false, null: false + t.string "old_emails", default: [], array: true t.string "phone_number", default: "" - t.boolean "receive_sms_notifications", default: false, null: false t.boolean "receive_email_notifications", default: true - t.string "confirmation_token" - t.datetime "confirmed_at" - t.datetime "confirmation_sent_at" - t.string "unconfirmed_email" - t.string "old_emails", default: [], array: true t.boolean "receive_reimbursement_email", default: false - t.boolean "monthly_learning_hours_report", default: false, null: false - t.datetime "date_of_birth" + t.boolean "receive_sms_notifications", default: false, null: false + t.datetime "reset_password_sent_at", precision: nil + t.string "reset_password_token" + t.integer "sign_in_count", default: 0, null: false + t.string "type" + t.string "unconfirmed_email" + t.datetime "updated_at", null: false t.index ["casa_org_id"], name: "index_users_on_casa_org_id" t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true t.index ["email"], name: "index_users_on_email", unique: true From 8152c6efb132a8489c62167be7d8813bb8203cbc Mon Sep 17 00:00:00 2001 From: Stefanni Brasil Date: Thu, 18 Jun 2026 14:39:37 -0600 Subject: [PATCH 6/8] bring these back --- config/environments/development.rb | 2 +- config/environments/production.rb | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/config/environments/development.rb b/config/environments/development.rb index d4fc67b336..cd8e628947 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -21,7 +21,7 @@ config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true config.cache_store = :memory_store - config.public_file_server.headers = { "cache-control" => "public, max-age=#{2.days.to_i}" } + config.public_file_server.headers = {"cache-control" => "public, max-age=#{2.days.to_i}"} else config.action_controller.perform_caching = false config.cache_store = :null_store diff --git a/config/environments/production.rb b/config/environments/production.rb index f5675af94f..c76e06bd5b 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -78,6 +78,11 @@ # Replace the default in-process and non-durable queuing backend for Active Job. # config.active_job.queue_adapter = :resque + # Use a real queuing backend for Active Job (and separate queues per environment). + config.active_job.queue_adapter = :delayed_job + + config.action_mailer.perform_caching = false + # Ignore bad email addresses and do not raise email delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors. # config.action_mailer.raise_delivery_errors = false From 972ce9e08888b0c47c8053b733d2f4905604aff1 Mon Sep 17 00:00:00 2001 From: Stefanni Brasil Date: Thu, 18 Jun 2026 15:10:38 -0600 Subject: [PATCH 7/8] Keep random date simple After the upgrade, this test was raising this error: ``` Failure/Error: ActiveRecord::Tasks::DatabaseTasks.load_seed ArgumentError: cannot load complex into simple # ./db/seeds/db_populator.rb:143:in 'block in DbPopulator#create_cases' # ./db/seeds/db_populator.rb:137:in 'Integer#times' # ./db/seeds/db_populator.rb:137:in 'DbPopulator#create_cases' ``` Keeping the date to a simpler rand generation solves the problem. --- db/seeds/db_populator.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/db/seeds/db_populator.rb b/db/seeds/db_populator.rb index a5080cd4a7..f4fccbc067 100644 --- a/db/seeds/db_populator.rb +++ b/db/seeds/db_populator.rb @@ -139,7 +139,6 @@ def create_cases(casa_org, options) court_date = generate_court_date court_report_submitted = index.even? - new_casa_case = CasaCase.find_by(case_number: case_number) birth_month_year_youth = @case_fourteen_years_old ? ((Date.today - 18.year)..(Date.today - CasaCase::TRANSITION_AGE.year)).to_a.sample : ((Date.today - 18.year)..(Date.today - 1.year)).to_a.sample new_casa_case ||= CasaCase.find_or_create_by!( casa_org_id: casa_org.id, @@ -147,7 +146,7 @@ def create_cases(casa_org, options) court_report_submitted_at: court_report_submitted ? Date.today : nil, court_report_status: court_report_submitted ? :submitted : :not_submitted, birth_month_year_youth: birth_month_year_youth, - date_in_care: Date.today - (rand * 1500) + date_in_care: Date.today - rand(1500) ) new_court_date = CourtDate.find_or_create_by!( casa_case: new_casa_case, From baaddc4f156a79af7d47b3d45870c1e389d594cb Mon Sep 17 00:00:00 2001 From: Stefanni Brasil Date: Thu, 18 Jun 2026 15:23:28 -0600 Subject: [PATCH 8/8] linter --- config/environments/production.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/environments/production.rb b/config/environments/production.rb index c76e06bd5b..bf55bcbc53 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -42,7 +42,7 @@ config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? # Cache assets for far-future expiry since they are all digest stamped. - config.public_file_server.headers = { "cache-control" => "public, max-age=#{1.year.to_i}" } + config.public_file_server.headers = {"cache-control" => "public, max-age=#{1.year.to_i}"} # Enable serving of images, stylesheets, and JavaScripts from an asset server. # config.asset_host = "http://assets.example.com"