From befe33d566c04d9c7d217148806c9c39c1302e18 Mon Sep 17 00:00:00 2001 From: Jay Varner Date: Tue, 11 Aug 2026 12:50:10 -0400 Subject: [PATCH 1/5] Bump roo 2.10.1 -> 3.0.0 and httparty 0.20.0 -> 0.24.2 Both deferred from the earlier dependency-hardening PR since they're major version bumps needing their own verification. roo 3.0 has no API-level breaking changes to spreadsheet reading (open/cell access/sheet iteration) per its changelog - just needs Ruby 3.1+ (have 3.4.10) and pulls rubyzip to 3.x, unconstrained by anything else in the Gemfile. httparty 0.24.2 fixes a High-severity SSRF/API-key-leakage CVE (GHSA-hm5p-x4rq-38w4) by restricting credential-forwarding on redirects to same-host. Every call site in this app (lib/import.rb, app/jobs/import_data_job.rb) hits a single hardcoded host directly, with no base_uri set and no credentials passed, so no behavior change expected - verified via full suite + clean boot (no dedicated spec coverage exists for either file either way). Verified: full suite (308 examples, 0 failures), rubocop clean. Co-Authored-By: Claude Sonnet 5 --- Gemfile | 4 ++-- Gemfile.lock | 25 +++++++++++++------------ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Gemfile b/Gemfile index e00eeee..87e87f9 100644 --- a/Gemfile +++ b/Gemfile @@ -84,9 +84,9 @@ gem 'acts-as-taggable-on', '~> 13.0' gem 'administrate-field-list', '~> 0.0.6' -gem 'httparty', '~> 0.20.0' +gem 'httparty', '~> 0.24.0' -gem 'roo', '~> 2.9' +gem 'roo', '~> 3.0' gem 'namae', '~> 1.1' diff --git a/Gemfile.lock b/Gemfile.lock index 3b4bc5b..a70b141 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -184,8 +184,9 @@ GEM globalid (1.2.1) activesupport (>= 6.1) hashie (5.0.0) - httparty (0.20.0) - mime-types (~> 3.0) + httparty (0.24.2) + csv + mini_mime (>= 1.0.0) multi_xml (>= 0.5.2) i18n (1.14.8) concurrent-ruby (~> 1.0) @@ -230,17 +231,14 @@ GEM net-smtp marcel (1.2.1) matrix (0.4.3) - mime-types (3.5.2) - mime-types-data (~> 3.2015) - mime-types-data (3.2024.1203) mini_magick (4.13.2) mini_mime (1.1.5) mini_portile2 (2.8.9) minitest (5.25.5) msgpack (1.8.4) multi_json (1.21.1) - multi_xml (0.7.2) - bigdecimal (~> 3.1) + multi_xml (0.9.1) + bigdecimal (>= 3.1, < 5) namae (1.2.0) racc (~> 1.7) net-http (0.9.1) @@ -337,9 +335,12 @@ GEM reline (0.5.12) io-console (~> 0.5) rexml (3.4.4) - roo (2.10.1) + roo (3.0.0) + base64 (~> 0.2) + csv (~> 3) + logger (~> 1) nokogiri (~> 1) - rubyzip (>= 1.3.0, < 3.0.0) + rubyzip (>= 3.0.0, < 4.0.0) rspec-core (3.13.6) rspec-support (~> 3.13.0) rspec-expectations (3.13.5) @@ -386,7 +387,7 @@ GEM ruby-vips (2.2.5) ffi (~> 1.12) logger - rubyzip (2.3.2) + rubyzip (3.4.1) sassc (2.4.0) ffi (~> 1.9) sassc-rails (2.1.2) @@ -484,7 +485,7 @@ DEPENDENCIES elasticsearch (~> 8) factory_bot_rails faker - httparty (~> 0.20.0) + httparty (~> 0.24.0) image_processing (~> 1.2) importmap-rails (~> 2.0) jbuilder (~> 2.11) @@ -494,7 +495,7 @@ DEPENDENCIES puma (~> 5.0) rack-cors rails (~> 8.1.3) - roo (~> 2.9) + roo (~> 3.0) rspec-rails rubocop rubocop-factory_bot From 41caef763b3e2ecfaabf8fa68a047c4fc65ef034 Mon Sep 17 00:00:00 2001 From: Jay Varner Date: Tue, 11 Aug 2026 13:30:17 -0400 Subject: [PATCH 2/5] Bump searchkick 5.3.1 -> 6.1.2 No breaking changes to the .search API (where/load/order) per the changelog. Removed its hard dependency on the elasticsearch gem (now optional, bring-your-own client) - decoupled from any future ES9 bump, not blocked by it. Surfaced two real, pre-existing bugs neither caught by tests before: - LettersController/EntitiesController's `before_action :reindex` calls `Letter.reindex`/`Entity.reindex` (class-level, full reindex) with no explicit mode, relying on Searchkick's default mode resolution to pick a synchronous reindex before the search that immediately follows. That resolution (Searchkick::Index#reindex_records) falls back to the model's own `callbacks:` searchkick option when no mode is given - and Searchable sets `callbacks: :async`. Whether that fallback applied to explicit `.reindex` calls the same way in 5.x is unclear, but it does now: the reindex enqueued an async job instead of running inline, and the search that followed sometimes ran before it completed, intermittently missing the ES mapping entirely ("No mapping found for [date]"). Fixed by passing `mode: :inline` explicitly in both controllers' reindex methods. - LettersController#letters_from_results called `letter.orgins` (typo for `origins`) on a Searchkick::HashWrapper. 5.x's HashWrapper silently returned nil for the typo'd key; 6.x raises NoMethodError instead. Fixed the typo and added regression coverage - nothing had ever asserted on the `origins` key in a letters index response before. Verified: full suite (309 examples, 0 failures), rubocop clean. Co-Authored-By: Claude Sonnet 5 --- Gemfile.lock | 6 ++---- app/controllers/entities_controller.rb | 8 ++++++-- app/controllers/letters_controller.rb | 10 +++++++--- spec/requests/letters_spec.rb | 11 +++++++++++ 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index a70b141..d4da143 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -183,7 +183,6 @@ GEM raabro (~> 1.4) globalid (1.2.1) activesupport (>= 6.1) - hashie (5.0.0) httparty (0.24.2) csv mini_mime (>= 1.0.0) @@ -396,9 +395,8 @@ GEM sprockets (> 3.0) sprockets-rails tilt - searchkick (5.3.1) - activemodel (>= 6.1) - hashie + searchkick (6.1.2) + activemodel (>= 7.2) securerandom (0.3.2) selenium-devtools (0.151.0) selenium-webdriver (~> 4.2) diff --git a/app/controllers/entities_controller.rb b/app/controllers/entities_controller.rb index 6ffd2c7..073cd32 100644 --- a/app/controllers/entities_controller.rb +++ b/app/controllers/entities_controller.rb @@ -69,8 +69,12 @@ def letters private def reindex - Entity.reindex if ENV['RAILS_ENV'] == 'test' - PublishedEntity.reindex if ENV['RAILS_ENV'] == 'test' + # mode: :inline forces a synchronous reindex regardless of Searchable's + # `callbacks: :async` option - searchkick's default mode resolution falls back to + # the model's callbacks option (see Searchkick::Index#reindex_records), so without + # this the search immediately below could run against a not-yet-indexed record. + Entity.reindex(mode: :inline) if ENV['RAILS_ENV'] == 'test' + PublishedEntity.reindex(mode: :inline) if ENV['RAILS_ENV'] == 'test' rescue Searchkick::Error end diff --git a/app/controllers/letters_controller.rb b/app/controllers/letters_controller.rb index 94434e9..96f1ed8 100644 --- a/app/controllers/letters_controller.rb +++ b/app/controllers/letters_controller.rb @@ -55,7 +55,7 @@ def letters_from_results(results) volume: letter.volume, recipients: letter.recipients, destinations: letter.destinations, - origins: letter.orgins, + origins: letter.origins, mentions: letter.mentions } end @@ -134,8 +134,12 @@ def set_filters # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity def reindex - Letter.reindex if ENV['RAILS_ENV'] == 'test' - PublishedLetter.reindex if ENV['RAILS_ENV'] == 'test' + # mode: :inline forces a synchronous reindex regardless of Searchable's + # `callbacks: :async` option - searchkick's default mode resolution falls back to + # the model's callbacks option (see Searchkick::Index#reindex_records), so without + # this the search immediately below could run against a not-yet-indexed record. + Letter.reindex(mode: :inline) if ENV['RAILS_ENV'] == 'test' + PublishedLetter.reindex(mode: :inline) if ENV['RAILS_ENV'] == 'test' end # Only allow a list of trusted parameters through. diff --git a/spec/requests/letters_spec.rb b/spec/requests/letters_spec.rb index 04ef8bf..81844e8 100644 --- a/spec/requests/letters_spec.rb +++ b/spec/requests/letters_spec.rb @@ -102,6 +102,17 @@ expect(json[:letters].count).to eq(9) end + # Regression test: LettersController#letters_from_results called `letter.orgins` + # (typo for `origins`) on a Searchkick::HashWrapper. Searchkick 5.x silently + # returned nil for the typo'd key; 6.x raises NoMethodError instead, surfacing a + # bug that was always there but never covered - nothing asserted on the `origins` + # key in a response before this. + it 'includes the origins of a letter' do + create(:published_letter, origins: create_list(:place_entity, 1, label: 'Reynoldstown')) + get "#{letters_url}.json" + expect(json[:letters].first[:origins]).to eq(['Reynoldstown']) + end + it 'returns letters with start_date param' do create_list(:published_letter, 10) create(:published_letter, date: DateTime.new(1961, 2, 22)) From 49a1d679fca10ccddaab03ace574de2dd0bcc634 Mon Sep 17 00:00:00 2001 From: Jay Varner Date: Tue, 11 Aug 2026 14:28:20 -0400 Subject: [PATCH 3/5] Bump image_processing 1.14.0 -> 2.0.3 Fixes several real RCE vulnerabilities (remote code execution via user-influenced operation names through #operation/#method_missing/#send, and unsafe minimagick loader/saver option names). mini_magick/ruby-vips became soft dependencies in 2.0 and must be added explicitly now - image_processing 1.x's gemspec hard-required both unconditionally. Initially added mini_magick, assuming it was the active processor since Rails defaults ActiveStorage.variant_processor to :mini_magick. That was wrong: this app calls config.load_defaults 7.0 (config/application.rb), and Rails' 7.0 defaults block (config/application/configuration.rb) unconditionally sets config.active_storage.variant_processor = :vips - vips has been the actually-active processor the whole time, with mini_magick present only as an unused transitive dependency. Confirmed by generating a real image variant, not just booting cleanly. Added ruby-vips instead. Verified: full suite (309 examples, 0 failures), rubocop clean, and an actual end-to-end variant generation via `rails runner` (attach a real image, call .variant(...).processed, confirm it produces a real blob) - not just a clean boot, since this exact class of bug (config silently depending on a gem that happened to be present transitively) only shows up when the feature is actually exercised. Co-Authored-By: Claude Sonnet 5 --- Gemfile | 8 +++++++- Gemfile.lock | 10 ++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Gemfile b/Gemfile index 87e87f9..e8d561c 100644 --- a/Gemfile +++ b/Gemfile @@ -33,7 +33,13 @@ gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby] gem 'bootsnap', require: false # Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images] -gem 'image_processing', '~> 1.2' +gem 'image_processing', '~> 2.0' +# mini_magick/ruby-vips became soft dependencies of image_processing in 2.0 and must be +# added explicitly. This app's config.load_defaults 7.0 (config/application.rb) sets +# config.active_storage.variant_processor = :vips - vips is the actually-active processor, +# not mini_magick (previously present only as an unused transitive dependency of +# image_processing 1.x's gemspec, which required both backends unconditionally). +gem 'ruby-vips', '~> 2.0' # Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible gem 'rack-cors' diff --git a/Gemfile.lock b/Gemfile.lock index d4da143..4c480d9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -189,9 +189,7 @@ GEM multi_xml (>= 0.5.2) i18n (1.14.8) concurrent-ruby (~> 1.0) - image_processing (1.13.0) - mini_magick (>= 4.9.5, < 5) - ruby-vips (>= 2.0.17, < 3) + image_processing (2.0.3) importmap-rails (2.0.3) actionpack (>= 6.0.0) activesupport (>= 6.0.0) @@ -230,7 +228,6 @@ GEM net-smtp marcel (1.2.1) matrix (0.4.3) - mini_magick (4.13.2) mini_mime (1.1.5) mini_portile2 (2.8.9) minitest (5.25.5) @@ -383,7 +380,7 @@ GEM rubocop (~> 1.61) rubocop-rspec (~> 3, >= 3.0.1) ruby-progressbar (1.13.0) - ruby-vips (2.2.5) + ruby-vips (2.3.0) ffi (~> 1.12) logger rubyzip (3.4.1) @@ -484,7 +481,7 @@ DEPENDENCIES factory_bot_rails faker httparty (~> 0.24.0) - image_processing (~> 1.2) + image_processing (~> 2.0) importmap-rails (~> 2.0) jbuilder (~> 2.11) kaminari (~> 1.2) @@ -500,6 +497,7 @@ DEPENDENCIES rubocop-rails rubocop-rspec rubocop-rspec_rails + ruby-vips (~> 2.0) sassc-rails searchkick selenium-devtools From a4de62893ac87cd85806e3f8aa96edac50308f2a Mon Sep 17 00:00:00 2001 From: Jay Varner Date: Tue, 11 Aug 2026 14:48:29 -0400 Subject: [PATCH 4/5] Bump puma 5.6.9 -> 8.0.2 Reviewed all four majors' upgrade guides (6.0/7.0/8.0-Upgrade.md) for anything that could affect this app: hook renames, removed Server#min/ max_threads, HTTP method allowlisting, response header lowercasing - none of it touches config/puma.rb (no hooks, no workers/cluster mode configured) or anything this app depends on. The one real behavioral change: Puma 8 defaults to binding IPv6 (::) instead of IPv4 (0.0.0.0) when a non-loopback IPv6 interface is available. This app deploys to AWS ECS/Fargate, and whether that networking setup handles the new default cleanly isn't verifiable from here. Puma's own upgrade guide recommends pinning the bind explicitly to preserve exact current behavior - added `port ENV.fetch('PORT', 3000), '0.0.0.0'` to config/puma.rb rather than gambling on it. Confirmed via a real (non-test- suite) server boot that it actually listens on 0.0.0.0 as pinned. No dependency conflicts - puma itself has no rack version constraint at all, unlike sidekiq 8 (which hard-requires rack >= 3.2.0 and was deferred alongside rack-cors for that reason). Verified: full suite (309 examples, 0 failures) including system specs, which boot a real Puma server via Capybara/Selenium - the exact code path Puma's own 6.0 changelog warned could break for gems depending on removed Server internals. rubocop clean. Co-Authored-By: Claude Sonnet 5 --- Gemfile | 2 +- Gemfile.lock | 4 ++-- config/puma.rb | 5 ++++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index e8d561c..f75148a 100644 --- a/Gemfile +++ b/Gemfile @@ -24,7 +24,7 @@ gem 'elasticsearch', '~> 8' gem 'searchkick' # Use the Puma web server [https://github.com/puma/puma] -gem 'puma', '~> 5.0' +gem 'puma', '~> 8.0' # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby] diff --git a/Gemfile.lock b/Gemfile.lock index 4c480d9..963bd93 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -277,7 +277,7 @@ GEM psych (5.1.2) stringio public_suffix (7.0.5) - puma (5.6.9) + puma (8.0.2) nio4r (~> 2.0) raabro (1.4.0) racc (1.8.1) @@ -487,7 +487,7 @@ DEPENDENCIES kaminari (~> 1.2) namae (~> 1.1) pg (~> 1.1) - puma (~> 5.0) + puma (~> 8.0) rack-cors rails (~> 8.1.3) roo (~> 3.0) diff --git a/config/puma.rb b/config/puma.rb index 1713441..7cdef17 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -17,7 +17,10 @@ # Specifies the `port` that Puma will listen on to receive requests; default is 3000. # -port ENV.fetch('PORT', 3000) +# Puma 8 defaults to binding IPv6 (::) instead of IPv4 (0.0.0.0) when a non-loopback +# IPv6 interface is available. Pinning the host explicitly preserves this app's +# existing IPv4 behavior regardless of Puma version or the host's network interfaces. +port ENV.fetch('PORT', 3000), '0.0.0.0' # Specifies the `environment` that Puma will run in. # From 252111f4af29f452a14af2f2f728fdd3ba0a4f25 Mon Sep 17 00:00:00 2001 From: Jay Varner Date: Tue, 11 Aug 2026 15:01:23 -0400 Subject: [PATCH 5/5] Bump dev/test toolchain: rspec-rails, shoulda-matchers, rubocop family rspec-rails 6.1.5 -> 8.0.4, shoulda-matchers 6.4.0 -> 8.0.1, rubocop 1.65.1 -> 1.89.0, rubocop-{rails,rspec,factory_bot,rspec_rails} to latest. All dev/test-only, no production runtime impact - verified by running the actual test suite and linter rather than reading changelogs, since a failure here surfaces immediately as a spec or lint failure. Applied the handful of newly-surfaced, genuinely safe rubocop fixes (redundant safe-navigation chains, a no-op Array#flatten after a string-returning #map, order('position') -> order(:position)) - all verified equivalent by reading the surrounding code, not blindly autocorrected. Deliberately left Rails/StrongParametersExpect alone (18 call sites across 6 controllers) even though most are auto-correctable: params.expect(...) raises ActionController::ParameterMissing/ParameterInvalid where bare params[:key] silently returns nil, a real behavior change across every public-facing endpoint in this app. That's its own deliberate audit, not a mechanical sweep. Also left Naming/PredicateMethod (flags a pre-existing dead `# TODO: Add authentication logic here` stub) and RSpec/Output (a false positive - it's rails_helper.rb boot-time boilerplate that prints and hard-exits on pending migrations, not a leftover debug print in a spec) - both pre-existing, out of scope here. Verified: full suite (309 examples, 0 failures) both before and after the manual fixes, rubocop clean except the deliberately-deferred items above. Co-Authored-By: Claude Sonnet 5 --- Gemfile.lock | 66 ++++++++++++++++------------ app/dashboards/entity_dashboard.rb | 1 + app/jobs/load_big_sam_job.rb | 3 +- app/models/concerns/entity_common.rb | 4 +- app/models/entity.rb | 4 +- app/models/faq.rb | 2 +- spec/factories/entities.rb | 3 -- spec/jobs/load_big_sam_job_spec.rb | 2 +- 8 files changed, 46 insertions(+), 39 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 963bd93..c7357ce 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -216,6 +216,7 @@ GEM kaminari-core (= 1.2.2) kaminari-core (1.2.2) language_server-protocol (3.17.0.6) + lint_roller (1.1.0) logger (1.6.6) loofah (2.25.2) crass (~> 1.0.2) @@ -274,6 +275,7 @@ GEM ast (~> 2.4.1) racc pg (1.5.9) + prism (1.9.0) psych (5.1.2) stringio public_suffix (7.0.5) @@ -345,40 +347,46 @@ GEM rspec-mocks (3.13.8) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-rails (6.1.5) - actionpack (>= 6.1) - activesupport (>= 6.1) - railties (>= 6.1) - rspec-core (~> 3.13) - rspec-expectations (~> 3.13) - rspec-mocks (~> 3.13) - rspec-support (~> 3.13) + rspec-rails (8.0.4) + actionpack (>= 7.2) + activesupport (>= 7.2) + railties (>= 7.2) + rspec-core (>= 3.13.0, < 5.0.0) + rspec-expectations (>= 3.13.0, < 5.0.0) + rspec-mocks (>= 3.13.0, < 5.0.0) + rspec-support (>= 3.13.0, < 5.0.0) rspec-support (3.13.7) - rubocop (1.65.1) + rubocop (1.89.0) json (~> 2.3) - language_server-protocol (>= 3.17.0) - parallel (~> 1.10) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.1.0) + parallel (>= 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 2.4, < 3.0) - rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.31.1, < 2.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.49.0, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.32.3) - parser (>= 3.3.1.0) - rubocop-factory_bot (2.26.1) - rubocop (~> 1.61) - rubocop-rails (2.26.2) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.50.0) + parser (>= 3.3.7.2) + prism (~> 1.7) + rubocop-factory_bot (2.28.0) + lint_roller (~> 1.1) + rubocop (~> 1.72, >= 1.72.1) + rubocop-rails (2.36.0) activesupport (>= 4.2.0) + lint_roller (~> 1.1) rack (>= 1.1) - rubocop (>= 1.52.0, < 2.0) - rubocop-ast (>= 1.31.1, < 2.0) - rubocop-rspec (3.0.5) - rubocop (~> 1.61) - rubocop-rspec_rails (2.30.0) - rubocop (~> 1.61) - rubocop-rspec (~> 3, >= 3.0.1) + rubocop (>= 1.75.0, < 2.0) + rubocop-ast (>= 1.44.0, < 2.0) + rubocop-rspec (3.10.2) + lint_roller (~> 1.1) + regexp_parser (>= 2.0) + rubocop (~> 1.86, >= 1.86.2) + rubocop-rspec_rails (2.32.0) + lint_roller (~> 1.1) + rubocop (~> 1.72, >= 1.72.1) + rubocop-rspec (~> 3.5) ruby-progressbar (1.13.0) ruby-vips (2.3.0) ffi (~> 1.12) @@ -403,8 +411,8 @@ GEM rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 4.0) websocket (~> 1.0) - shoulda-matchers (6.4.0) - activesupport (>= 5.2.0) + shoulda-matchers (8.0.1) + activesupport (>= 7.2) sidekiq (7.3.10) base64 connection_pool (>= 2.3.0, < 3) diff --git a/app/dashboards/entity_dashboard.rb b/app/dashboards/entity_dashboard.rb index 2c6101d..d55f8aa 100644 --- a/app/dashboards/entity_dashboard.rb +++ b/app/dashboards/entity_dashboard.rb @@ -4,6 +4,7 @@ class EntityDashboard < Administrate::BaseDashboard include ActionView::Helpers::SanitizeHelper + # ATTRIBUTE_TYPES # a hash that describes the type of each of the model's fields. # diff --git a/app/jobs/load_big_sam_job.rb b/app/jobs/load_big_sam_job.rb index e033577..191f072 100644 --- a/app/jobs/load_big_sam_job.rb +++ b/app/jobs/load_big_sam_job.rb @@ -5,6 +5,7 @@ class LoadBigSamJob < ApplicationJob include ActionView::Helpers::SanitizeHelper + queue_as :default # Raised to abandon a single row (e.g. an unparseable date) without treating it as a @@ -372,7 +373,7 @@ def get_entity(label: nil, type: nil, return_nil: false) def get_person(name) entity = nil names = Namae.parse(name).first - if names&.given && names&.family + if names&.given && names.family names.family = "Van #{names.family}" if names.particle&.downcase == 'van' names.family = "von #{names.family}" if names.particle&.downcase == 'von' names = mc_or_mac?(names) diff --git a/app/models/concerns/entity_common.rb b/app/models/concerns/entity_common.rb index 86adf35..1416591 100644 --- a/app/models/concerns/entity_common.rb +++ b/app/models/concerns/entity_common.rb @@ -198,7 +198,7 @@ def short_display lines.push("Date #{date_str}") if date_str.present? end - paragraphs = lines.map {|line| "

#{line}

" }.flatten.join.strip + paragraphs = lines.map {|line| "

#{line}

" }.join.strip Loofah.fragment("
#{paragraphs}
").scrub!(:prune).to_html end @@ -299,7 +299,7 @@ def full_display rows.push("See Also#{link_list}") if links.present? end - table_rows = rows.map {|row| "#{row}" }.flatten.join.strip + table_rows = rows.map {|row| "#{row}" }.join.strip Loofah.fragment("#{table_rows}
").scrub!(:prune).to_html end diff --git a/app/models/entity.rb b/app/models/entity.rb index dafc7b7..37287a6 100644 --- a/app/models/entity.rb +++ b/app/models/entity.rb @@ -104,9 +104,9 @@ def concat_label "#{event_types&.map(&:titleize)&.join(',')} #{description}".strip end when 'person' - if label && (last_name.nil? && first_name.nil?) + if label && last_name.nil? && first_name.nil? names = Namae.parse label - if names&.first&.given && names&.first&.family + if names&.first&.given && names&.first.family self.first_name = names.first.given self.last_name = names.first.family end diff --git a/app/models/faq.rb b/app/models/faq.rb index 8778860..1c07a89 100644 --- a/app/models/faq.rb +++ b/app/models/faq.rb @@ -4,7 +4,7 @@ class Faq < ApplicationRecord before_save :initial_position after_save :update_position - default_scope { order('position') } + default_scope { order(:position) } private diff --git a/spec/factories/entities.rb b/spec/factories/entities.rb index 865c590..52e8793 100644 --- a/spec/factories/entities.rb +++ b/spec/factories/entities.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -# rubocop:disable Layout/LineLength - FactoryBot.define do factory :entity do label { Faker::Movies::HitchhikersGuideToTheGalaxy.character } @@ -170,4 +168,3 @@ end end end -# rubocop:enable Layout/LineLength diff --git a/spec/jobs/load_big_sam_job_spec.rb b/spec/jobs/load_big_sam_job_spec.rb index aaf26b0..87464dd 100644 --- a/spec/jobs/load_big_sam_job_spec.rb +++ b/spec/jobs/load_big_sam_job_spec.rb @@ -262,7 +262,7 @@ def valid_row(overrides = {}) skipped = job.instance_variable_get(:@row_skipped) expect(skipped.size).to eq(1) expect(skipped.first[:code]).to eq('BAD') - expect(skipped.first[:reason]).to match(/bad date/) + expect(skipped.first[:reason]).to include('bad date') expect(Letter.find_by(legacy_pk: 955).code).to eq('GOOD') end