diff --git a/.ruby-version b/.ruby-version index a0891f5..84d6c67 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.3.4 +3.4.10 diff --git a/Gemfile b/Gemfile index 9b3924d..e00eeee 100644 --- a/Gemfile +++ b/Gemfile @@ -3,10 +3,18 @@ source 'https://rubygems.org' git_source(:github) {|_repo| "https://github.com/#{repo}.git" } -ruby '3.3.4' +ruby '3.4.10' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails', branch: 'main' -gem 'rails', '~> 7.2.1' +gem 'rails', '~> 8.1.3' + +# csv stopped being a Ruby default gem in 3.4+; httparty requires it internally +# without declaring it as a dependency, so it must be explicit here. +gem 'csv' + +# benchmark won't be a default gem starting in Ruby 4.0; mini_magick requires it +# internally without declaring it as a dependency. +gem 'benchmark' # Use postgresql as the database for Active Record gem 'pg', '~> 1.1' @@ -68,7 +76,11 @@ gem 'kaminari', '~> 1.2' gem 'jbuilder', '~> 2.11' -gem 'acts-as-taggable-on', '~> 11.0.0' +# 11.0.0 hard-pins activerecord < 8.0, which makes it impossible to install +# alongside Rails 8 at all - not a discretionary bump, a forced one. 12->13 has +# no breaking changes to the tag_list/for_context API ActsAsTaggableField uses +# (see CHANGELOG.md), only dropped-Ruby-version and added-Rails-version support. +gem 'acts-as-taggable-on', '~> 13.0' gem 'administrate-field-list', '~> 0.0.6' @@ -84,7 +96,7 @@ gem 'active_record_doctor', '~> 1.10' gem 'sidekiq', '>=7.2.2', '<8' -gem 'addressable', '~> 2.8' +gem 'addressable', '~> 2.9' gem 'importmap-rails', '~> 2.0' diff --git a/Gemfile.lock b/Gemfile.lock index a5c643d..3b4bc5b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,83 +1,87 @@ GEM remote: https://rubygems.org/ specs: - actioncable (7.2.1) - actionpack (= 7.2.1) - activesupport (= 7.2.1) + action_text-trix (2.1.19) + railties + actioncable (8.1.3.1) + actionpack (= 8.1.3.1) + activesupport (= 8.1.3.1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.2.1) - actionpack (= 7.2.1) - activejob (= 7.2.1) - activerecord (= 7.2.1) - activestorage (= 7.2.1) - activesupport (= 7.2.1) + actionmailbox (8.1.3.1) + actionpack (= 8.1.3.1) + activejob (= 8.1.3.1) + activerecord (= 8.1.3.1) + activestorage (= 8.1.3.1) + activesupport (= 8.1.3.1) mail (>= 2.8.0) - actionmailer (7.2.1) - actionpack (= 7.2.1) - actionview (= 7.2.1) - activejob (= 7.2.1) - activesupport (= 7.2.1) + actionmailer (8.1.3.1) + actionpack (= 8.1.3.1) + actionview (= 8.1.3.1) + activejob (= 8.1.3.1) + activesupport (= 8.1.3.1) mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (7.2.1) - actionview (= 7.2.1) - activesupport (= 7.2.1) + actionpack (8.1.3.1) + actionview (= 8.1.3.1) + activesupport (= 8.1.3.1) nokogiri (>= 1.8.5) - racc - rack (>= 2.2.4, < 3.2) + rack (>= 2.2.4) rack-session (>= 1.0.1) rack-test (>= 0.6.3) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) useragent (~> 0.16) - actiontext (7.2.1) - actionpack (= 7.2.1) - activerecord (= 7.2.1) - activestorage (= 7.2.1) - activesupport (= 7.2.1) + actiontext (8.1.3.1) + action_text-trix (~> 2.1.15) + actionpack (= 8.1.3.1) + activerecord (= 8.1.3.1) + activestorage (= 8.1.3.1) + activesupport (= 8.1.3.1) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.2.1) - activesupport (= 7.2.1) + actionview (8.1.3.1) + activesupport (= 8.1.3.1) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) active_record_doctor (1.14.0) activerecord (>= 4.2.0) - activejob (7.2.1) - activesupport (= 7.2.1) + activejob (8.1.3.1) + activesupport (= 8.1.3.1) globalid (>= 0.3.6) - activemodel (7.2.1) - activesupport (= 7.2.1) - activerecord (7.2.1) - activemodel (= 7.2.1) - activesupport (= 7.2.1) + activemodel (8.1.3.1) + activesupport (= 8.1.3.1) + activerecord (8.1.3.1) + activemodel (= 8.1.3.1) + activesupport (= 8.1.3.1) timeout (>= 0.4.0) - activestorage (7.2.1) - actionpack (= 7.2.1) - activejob (= 7.2.1) - activerecord (= 7.2.1) - activesupport (= 7.2.1) + activestorage (8.1.3.1) + actionpack (= 8.1.3.1) + activejob (= 8.1.3.1) + activerecord (= 8.1.3.1) + activesupport (= 8.1.3.1) marcel (~> 1.0) - activesupport (7.2.1) + activesupport (8.1.3.1) base64 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) tzinfo (~> 2.0, >= 2.0.5) - acts-as-taggable-on (11.0.0) - activerecord (>= 7.0, < 8.0) + uri (>= 0.13.1) + acts-as-taggable-on (13.0.0) + activerecord (>= 7.1, < 8.2) zeitwerk (>= 2.4, < 3.0) - addressable (2.8.7) - public_suffix (>= 2.0.2, < 7.0) + addressable (2.9.0) + public_suffix (>= 2.0.2, < 8.0) administrate (1.0.0) actionpack (>= 6.0, < 9.0) actionview (>= 6.0, < 9.0) @@ -92,7 +96,7 @@ GEM administrate-field-list (0.0.6) administrate rails (>= 5.0) - ast (2.4.2) + ast (2.4.3) aws-eventstream (1.4.0) aws-partitions (1.1278.0) aws-sdk-core (3.254.1) @@ -111,9 +115,10 @@ GEM aws-sigv4 (~> 1.5) aws-sigv4 (1.12.1) aws-eventstream (~> 1, >= 1.0.2) - base64 (0.2.0) - bigdecimal (3.1.8) - bootsnap (1.18.4) + base64 (0.3.0) + benchmark (0.5.0) + bigdecimal (3.1.9) + bootsnap (1.18.6) msgpack (~> 1.2) builder (3.3.0) capybara (3.40.0) @@ -125,19 +130,20 @@ GEM rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) - concurrent-ruby (1.3.4) + concurrent-ruby (1.3.8) connection_pool (2.4.1) - crass (1.0.6) + crass (1.0.7) cronex (0.15.0) tzinfo unicode (>= 0.4.4.5) - date (3.3.4) + csv (3.3.6) + date (3.5.1) debug (1.9.2) irb (~> 1.10) reline (>= 0.3.8) diff-lcs (1.5.1) - drb (2.2.1) - elastic-transport (8.5.2) + drb (2.2.3) + elastic-transport (8.5.3) faraday (< 3) multi_json elasticsearch (8.19.3) @@ -146,33 +152,33 @@ GEM ostruct elasticsearch-api (8.19.3) multi_json - erubi (1.13.0) - et-orbi (1.4.0) + erubi (1.13.1) + et-orbi (1.4.1) tzinfo - factory_bot (6.4.6) - activesupport (>= 5.0.0) - factory_bot_rails (6.4.3) - factory_bot (~> 6.4) + factory_bot (6.5.6) + activesupport (>= 6.1.0) + factory_bot_rails (6.4.4) + factory_bot (~> 6.5) railties (>= 5.0.0) faker (3.4.2) i18n (>= 1.8.11, < 2) - faraday (2.14.2) + faraday (2.14.3) faraday-net_http (>= 2.0, < 3.5) json logger faraday-net_http (3.4.4) net-http (~> 0.5) - ffi (1.17.0-aarch64-linux-gnu) - ffi (1.17.0-aarch64-linux-musl) - ffi (1.17.0-arm-linux-gnu) - ffi (1.17.0-arm-linux-musl) - ffi (1.17.0-arm64-darwin) - ffi (1.17.0-x86-linux-gnu) - ffi (1.17.0-x86-linux-musl) - ffi (1.17.0-x86_64-darwin) - ffi (1.17.0-x86_64-linux-gnu) - ffi (1.17.0-x86_64-linux-musl) - fugit (1.12.2) + ffi (1.17.4-aarch64-linux-gnu) + ffi (1.17.4-aarch64-linux-musl) + ffi (1.17.4-arm-linux-gnu) + ffi (1.17.4-arm-linux-musl) + ffi (1.17.4-arm64-darwin) + ffi (1.17.4-x86-linux-gnu) + ffi (1.17.4-x86-linux-musl) + ffi (1.17.4-x86_64-darwin) + ffi (1.17.4-x86_64-linux-gnu) + ffi (1.17.4-x86_64-linux-musl) + fugit (1.12.3) et-orbi (~> 1.4) raabro (~> 1.4) globalid (1.2.1) @@ -181,24 +187,24 @@ GEM httparty (0.20.0) mime-types (~> 3.0) multi_xml (>= 0.5.2) - i18n (1.14.5) + 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) - importmap-rails (2.0.1) + importmap-rails (2.0.3) actionpack (>= 6.0.0) activesupport (>= 6.0.0) railties (>= 6.0.0) io-console (0.7.2) - irb (1.14.0) + irb (1.14.3) rdoc (>= 4.0.0) reline (>= 0.4.2) jbuilder (2.12.0) actionview (>= 5.0.0) activesupport (>= 5.0.0) jmespath (1.6.2) - json (2.7.2) + json (2.7.6) kaminari (1.2.2) activesupport (>= 4.1.0) kaminari-actionview (= 1.2.2) @@ -211,105 +217,115 @@ GEM activerecord kaminari-core (= 1.2.2) kaminari-core (1.2.2) - language_server-protocol (3.17.0.3) - logger (1.6.0) - loofah (2.22.0) + language_server-protocol (3.17.0.6) + logger (1.6.6) + loofah (2.25.2) crass (~> 1.0.2) nokogiri (>= 1.12.0) - mail (2.8.1) + mail (2.9.1) + logger mini_mime (>= 0.1.1) net-imap net-pop net-smtp - marcel (1.0.4) + marcel (1.2.1) matrix (0.4.3) mime-types (3.5.2) mime-types-data (~> 3.2015) - mime-types-data (3.2024.0820) + mime-types-data (3.2024.1203) mini_magick (4.13.2) mini_mime (1.1.5) - minitest (5.25.1) - msgpack (1.7.2) + mini_portile2 (2.8.9) + minitest (5.25.5) + msgpack (1.8.4) multi_json (1.21.1) - multi_xml (0.7.1) + multi_xml (0.7.2) bigdecimal (~> 3.1) namae (1.2.0) racc (~> 1.7) net-http (0.9.1) uri (>= 0.11.1) - net-imap (0.4.14) + net-imap (0.6.6) date net-protocol net-pop (0.1.2) net-protocol net-protocol (0.2.2) timeout - net-smtp (0.5.0) + net-smtp (0.5.1) net-protocol - nio4r (2.7.3) - nokogiri (1.16.7-aarch64-linux) + nio4r (2.7.5) + nokogiri (1.19.4) + mini_portile2 (~> 2.8.2) racc (~> 1.4) - nokogiri (1.16.7-arm-linux) + nokogiri (1.19.4-aarch64-linux-gnu) racc (~> 1.4) - nokogiri (1.16.7-arm64-darwin) + nokogiri (1.19.4-aarch64-linux-musl) racc (~> 1.4) - nokogiri (1.16.7-x86-linux) + nokogiri (1.19.4-arm-linux-gnu) racc (~> 1.4) - nokogiri (1.16.7-x86_64-darwin) + nokogiri (1.19.4-arm-linux-musl) racc (~> 1.4) - nokogiri (1.16.7-x86_64-linux) + nokogiri (1.19.4-arm64-darwin) + racc (~> 1.4) + nokogiri (1.19.4-x86_64-darwin) + racc (~> 1.4) + nokogiri (1.19.4-x86_64-linux-gnu) + racc (~> 1.4) + nokogiri (1.19.4-x86_64-linux-musl) racc (~> 1.4) ostruct (0.6.3) parallel (1.26.3) - parser (3.3.4.2) + parser (3.3.12.0) ast (~> 2.4.1) racc - pg (1.5.7) + pg (1.5.9) psych (5.1.2) stringio - public_suffix (6.0.1) - puma (5.6.8) + public_suffix (7.0.5) + puma (5.6.9) nio4r (~> 2.0) raabro (1.4.0) racc (1.8.1) - rack (2.2.9) + rack (2.2.23) rack-cors (2.0.2) rack (>= 2.0.0) rack-session (1.0.2) rack (< 3) rack-test (2.1.0) rack (>= 1.3) - rackup (1.0.0) + rackup (1.0.1) rack (< 3) webrick - rails (7.2.1) - actioncable (= 7.2.1) - actionmailbox (= 7.2.1) - actionmailer (= 7.2.1) - actionpack (= 7.2.1) - actiontext (= 7.2.1) - actionview (= 7.2.1) - activejob (= 7.2.1) - activemodel (= 7.2.1) - activerecord (= 7.2.1) - activestorage (= 7.2.1) - activesupport (= 7.2.1) + rails (8.1.3.1) + actioncable (= 8.1.3.1) + actionmailbox (= 8.1.3.1) + actionmailer (= 8.1.3.1) + actionpack (= 8.1.3.1) + actiontext (= 8.1.3.1) + actionview (= 8.1.3.1) + activejob (= 8.1.3.1) + activemodel (= 8.1.3.1) + activerecord (= 8.1.3.1) + activestorage (= 8.1.3.1) + activesupport (= 8.1.3.1) bundler (>= 1.15.0) - railties (= 7.2.1) + railties (= 8.1.3.1) rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.6.0) - loofah (~> 2.21) - nokogiri (~> 1.14) - railties (7.2.1) - actionpack (= 7.2.1) - activesupport (= 7.2.1) + rails-html-sanitizer (1.7.1) + loofah (~> 2.25, >= 2.25.2) + 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.1.3.1) + actionpack (= 8.1.3.1) + activesupport (= 8.1.3.1) irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) thor (~> 1.0, >= 1.2.2) + tsort (>= 0.2) zeitwerk (~> 2.6) rainbow (3.1.1) rake (13.2.1) @@ -317,23 +333,22 @@ GEM psych (>= 4.0.0) redis-client (0.23.2) connection_pool - regexp_parser (2.9.2) - reline (0.5.9) + regexp_parser (2.9.3) + reline (0.5.12) io-console (~> 0.5) - rexml (3.3.6) - strscan + rexml (3.4.4) roo (2.10.1) nokogiri (~> 1) rubyzip (>= 1.3.0, < 3.0.0) - rspec-core (3.13.0) + rspec-core (3.13.6) rspec-support (~> 3.13.0) - rspec-expectations (3.13.2) + rspec-expectations (3.13.5) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-mocks (3.13.1) + rspec-mocks (3.13.8) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-rails (6.1.4) + rspec-rails (6.1.5) actionpack (>= 6.1) activesupport (>= 6.1) railties (>= 6.1) @@ -341,7 +356,7 @@ GEM rspec-expectations (~> 3.13) rspec-mocks (~> 3.13) rspec-support (~> 3.13) - rspec-support (3.13.1) + rspec-support (3.13.7) rubocop (1.65.1) json (~> 2.3) language_server-protocol (>= 3.17.0) @@ -353,22 +368,22 @@ GEM rubocop-ast (>= 1.31.1, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.32.1) + rubocop-ast (1.32.3) parser (>= 3.3.1.0) rubocop-factory_bot (2.26.1) rubocop (~> 1.61) - rubocop-rails (2.26.0) + rubocop-rails (2.26.2) activesupport (>= 4.2.0) rack (>= 1.1) rubocop (>= 1.52.0, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) - rubocop-rspec (3.0.4) + rubocop-rspec (3.0.5) rubocop (~> 1.61) rubocop-rspec_rails (2.30.0) rubocop (~> 1.61) rubocop-rspec (~> 3, >= 3.0.1) ruby-progressbar (1.13.0) - ruby-vips (2.2.2) + ruby-vips (2.2.5) ffi (~> 1.12) logger rubyzip (2.3.2) @@ -383,7 +398,7 @@ GEM searchkick (5.3.1) activemodel (>= 6.1) hashie - securerandom (0.3.1) + securerandom (0.3.2) selenium-devtools (0.151.0) selenium-webdriver (~> 4.2) selenium-webdriver (4.46.0) @@ -394,12 +409,12 @@ GEM websocket (~> 1.0) shoulda-matchers (6.4.0) activesupport (>= 5.2.0) - sidekiq (7.3.8) + sidekiq (7.3.10) base64 - connection_pool (>= 2.3.0) + connection_pool (>= 2.3.0, < 3) logger - rack (>= 2.2.4) - redis-client (>= 0.22.2) + rack (>= 2.2.4, < 3.3) + redis-client (>= 0.23.0, < 1) sidekiq-cron (2.4.0) cronex (>= 0.13.0) fugit (~> 1.8, >= 1.11.1) @@ -413,27 +428,28 @@ GEM actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) - stringio (3.1.1) - strscan (3.1.0) - thor (1.3.1) + stringio (3.1.9) + thor (1.3.2) tilt (2.8.0) - timeout (0.4.1) + timeout (0.6.1) trix-rails (2.4.0) rails (> 4.1) + tsort (0.2.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode (0.4.4.5) unicode-display_width (2.5.0) uri (1.1.1) - useragent (0.16.10) - webrick (1.8.1) + useragent (0.16.11) + webrick (1.8.2) websocket (1.2.11) - websocket-driver (0.7.6) + websocket-driver (0.8.2) + base64 websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.17) + zeitwerk (2.6.18) PLATFORMS aarch64-linux @@ -452,16 +468,18 @@ PLATFORMS DEPENDENCIES active_record_doctor (~> 1.10) - acts-as-taggable-on (~> 11.0.0) - addressable (~> 2.8) + acts-as-taggable-on (~> 13.0) + addressable (~> 2.9) administrate administrate-field-active_storage (~> 0.4.1) administrate-field-jsonb administrate-field-list (~> 0.0.6) aws-sdk-rails (~> 5.0) aws-sdk-ses (~> 1.0) + benchmark bootsnap capybara + csv debug elasticsearch (~> 8) factory_bot_rails @@ -475,7 +493,7 @@ DEPENDENCIES pg (~> 1.1) puma (~> 5.0) rack-cors - rails (~> 7.2.1) + rails (~> 8.1.3) roo (~> 2.9) rspec-rails rubocop @@ -495,7 +513,7 @@ DEPENDENCIES tzinfo-data RUBY VERSION - ruby 3.3.4p94 + ruby 3.4.10p104 BUNDLED WITH 2.5.11 diff --git a/app/fields/acts_as_taggable_field.rb b/app/fields/acts_as_taggable_field.rb index 528a3a3..ca78488 100644 --- a/app/fields/acts_as_taggable_field.rb +++ b/app/fields/acts_as_taggable_field.rb @@ -18,6 +18,22 @@ def context options.fetch(:context, @attribute) end + # Administrate::Field::Base#read_value (called from #initialize, before + # #attribute is overridden below has a chance to matter) lazily fetches data via + # `resource.try(attribute)` - and that `attribute` call is polymorphic, so it hits + # our own override below instead of the raw `:tags` attribute key, fetching + # `resource.tag_list` (an array of tag-name strings) instead of `resource.tags` + # (real ActsAsTaggableOn::Tag records). #tags/#delimited/#truncate all expect the + # latter, so this re-derives the same logic using @attribute (the raw ivar) rather + # than the overridden #attribute method. + def read_value(data) + if options.key?(:getter) + return options[:getter].respond_to?(:call) ? options[:getter].call(self) : resource.try(options[:getter]) + end + + data.nil? ? resource.try(@attribute) : data + end + # acts_as_taggable_on exposes a `_list` virtual attribute # (e.g. `tag_list` for the `:tags` context) for reading/writing a comma-delimited # tag string - this field operates on that attribute rather than the raw `tags` diff --git a/app/workers/resave_all_letters_worker.rb b/app/workers/resave_all_letters_worker.rb index a84ef58..5d95750 100644 --- a/app/workers/resave_all_letters_worker.rb +++ b/app/workers/resave_all_letters_worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ResaveAllLettersWorker include Sidekiq::Job diff --git a/bin/dev b/bin/dev new file mode 100644 index 0000000..5f91c20 --- /dev/null +++ b/bin/dev @@ -0,0 +1,2 @@ +#!/usr/bin/env ruby +exec "./bin/rails", "server", *ARGV diff --git a/bin/rubocop b/bin/rubocop new file mode 100644 index 0000000..5a20504 --- /dev/null +++ b/bin/rubocop @@ -0,0 +1,8 @@ +#!/usr/bin/env ruby +require "rubygems" +require "bundler/setup" + +# Explicit RuboCop config increases performance slightly while avoiding config confusion. +ARGV.unshift("--config", File.expand_path("../.rubocop.yml", __dir__)) + +load Gem.bin_path("rubocop", "rubocop") diff --git a/config/importmap.rb b/config/importmap.rb index 7fdb198..7c2f1f5 100644 --- a/config/importmap.rb +++ b/config/importmap.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + # Pin npm packages by running ./bin/importmap pin 'application' pin 'moment' # @2.30.1 -pin "js-datepicker" # @5.18.3 +pin 'js-datepicker' # @5.18.3 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 0000000..8f20895 --- /dev/null +++ b/config/initializers/new_framework_defaults_8_1.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +# 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/spec/fields/acts_as_taggable_field_spec.rb b/spec/fields/acts_as_taggable_field_spec.rb index 7abbc56..d82b9bd 100644 --- a/spec/fields/acts_as_taggable_field_spec.rb +++ b/spec/fields/acts_as_taggable_field_spec.rb @@ -22,6 +22,24 @@ field = described_class.new(:tags, %w[a b], nil) expect(field.tags).to eq(%w[a b]) end + + it 'fetches real Tag records from the resource when constructed the way Administrate ' \ + 'actually builds fields (data: nil, resource: given), not tag_list name strings' do + # Administrate::Field::Base#read_value calls `resource.try(attribute)` when data is + # nil - and that `attribute` call is polymorphic, landing on this class's own + # #attribute override (returns "tag_list") rather than the raw :tags attribute this + # field was constructed with. A prior version of #read_value used that overridden + # #attribute directly, so this fetched mention.tag_list (tag-name strings) instead of + # mention.tags (real Tag records), and _show.html.erb's `tag.name` raised + # NoMethodError on a String. Only reproducible by exercising the real construction + # path (data: nil) - constructing with data already populated skips read_value + # entirely, which is why this went undetected until manual browser verification. + mention = create(:mention, tag_list: 'battle, correspondence') + field = described_class.new(:tags, nil, nil, resource: mention) + + expect(field.tags).to all(be_a(ActsAsTaggableOn::Tag)) + expect(field.tags.map(&:name)).to contain_exactly('battle', 'correspondence') + end end describe '#delimited' do diff --git a/spec/jobs/load_big_sam_job_spec.rb b/spec/jobs/load_big_sam_job_spec.rb index 4271655..aaf26b0 100644 --- a/spec/jobs/load_big_sam_job_spec.rb +++ b/spec/jobs/load_big_sam_job_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' require 'fileutils' diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index a9bc56b..4c3b332 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -49,7 +49,7 @@ # ActiveStorage::Current is a CurrentAttributes subclass — its values are # reset by ActiveSupport::Executor after each inline job. Setting url_options # in before(:each) ensures it's present whenever a spec calls .url. - config.before { ActiveStorage::Current.url_options = { host: ENV['RAILS_HOST'] } } + config.before { ActiveStorage::Current.url_options = { host: ENV.fetch('RAILS_HOST', nil) } } # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures config.fixture_paths = [Rails.root.join('spec', 'fixtures'), Rails.root.join('spec', 'fixtures', 'files')] diff --git a/spec/requests/admin/mentions_spec.rb b/spec/requests/admin/mentions_spec.rb index bc9506c..10363c3 100644 --- a/spec/requests/admin/mentions_spec.rb +++ b/spec/requests/admin/mentions_spec.rb @@ -14,6 +14,16 @@ get admin_mentions_path, headers: admin_auth_headers expect(response).to have_http_status(:ok) end + + # Regression test: ActsAsTaggableField's #tags previously blew up on a real tagged + # mention outside of a bare smoke test, since the untagged factory default never + # exercised the field's actual data-fetching path (see acts_as_taggable_field_spec.rb). + it 'renders the tags of a tagged mention' do + create(:mention, tag_list: 'battle, correspondence') + get admin_mentions_path, headers: admin_auth_headers + expect(response).to have_http_status(:ok) + expect(response.body).to include('battle').and include('correspondence') + end end describe 'GET show' do @@ -22,6 +32,13 @@ get admin_mention_path(mention), headers: admin_auth_headers expect(response).to have_http_status(:ok) end + + it 'renders the tags of a tagged mention' do + mention = create(:mention, tag_list: 'battle, correspondence') + get admin_mention_path(mention), headers: admin_auth_headers + expect(response).to have_http_status(:ok) + expect(response.body).to include('battle').and include('correspondence') + end end describe 'GET new' do @@ -37,5 +54,12 @@ get edit_admin_mention_path(mention), headers: admin_auth_headers expect(response).to have_http_status(:ok) end + + it 'pre-populates the tag list input of a tagged mention' do + mention = create(:mention, tag_list: 'battle, correspondence') + get edit_admin_mention_path(mention), headers: admin_auth_headers + expect(response).to have_http_status(:ok) + expect(response.body).to include('value="battle, correspondence"') + end end end