diff --git a/Gemfile b/Gemfile index d283ff8f1..d1d92b9d3 100644 --- a/Gemfile +++ b/Gemfile @@ -78,7 +78,7 @@ gem "carrierwave-base64" gem "mini_magick" # Mail -gem "mjml-rails" +gem "mjml-rails", "~> 4.0" gem "letter_opener_web" gem "sendgrid-actionmailer" diff --git a/Gemfile.lock b/Gemfile.lock index 55276ebaa..b84e20400 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -10,10 +10,10 @@ GIT GIT remote: https://github.com/activeadmin-plugins/active_admin_sidebar.git - revision: 18b38b0586192cc0acab70b914b3536ca5be04de + revision: 463f5e33f8fb12001748ab4a2f4b13ede0a09607 specs: - active_admin_sidebar (2.0.0) - activeadmin + active_admin_sidebar (3.0.0) + activeadmin (>= 3.0, < 4.0) GIT remote: https://github.com/tsubik/activeadmin-globalize.git @@ -135,8 +135,8 @@ GEM timeout (>= 0.4.0) activerecord-import (2.2.0) activerecord (>= 4.2) - activerecord-postgis-adapter (10.0.2) - activerecord (~> 7.2.0) + activerecord-postgis-adapter (10.0.3) + activerecord (~> 7.2) rgeo-activerecord (~> 8.0.0) activestorage (7.2.3.1) actionpack (= 7.2.3.1) @@ -159,7 +159,7 @@ GEM acts_as_list (1.2.6) activerecord (>= 6.1) activesupport (>= 6.1) - addressable (2.8.9) + addressable (2.9.0) public_suffix (>= 2.0.2, < 8.0) airbrussh (1.6.1) sshkit (>= 1.6.1, != 1.7.0) @@ -174,14 +174,14 @@ GEM base64 (0.3.0) bcrypt (3.1.22) benchmark (0.5.0) - bigdecimal (4.1.0) + bigdecimal (4.1.2) bindex (0.8.1) - bootsnap (1.23.0) + bootsnap (1.24.3) msgpack (~> 1.2) brakeman (8.0.4) racc builder (3.3.0) - bullet (8.1.0) + bullet (8.1.1) activesupport (>= 3.0.0) uniform_notifier (~> 1.11) bundler-audit (0.9.3) @@ -274,15 +274,15 @@ GEM dotenv (= 2.8.1) railties (>= 3.2) drb (2.2.3) - erb (6.0.2) + erb (6.0.4) erubi (1.13.1) - execjs (2.10.0) - factory_bot (6.5.6) + execjs (2.10.1) + factory_bot (6.6.0) activesupport (>= 6.1.0) factory_bot_rails (6.5.1) factory_bot (~> 6.5) railties (>= 6.1.0) - faker (3.6.1) + faker (3.8.0) i18n (>= 1.8.11, < 2) faraday (2.14.1) faraday-net_http (>= 2.0, < 3.5) @@ -300,7 +300,7 @@ GEM websocket-driver (~> 0.7) ffi (1.17.4) ffi (1.17.4-x86_64-linux-gnu) - ffi-compiler (1.3.2) + ffi-compiler (1.4.2) ffi (>= 1.15.5) rake formtastic (6.0.0) @@ -334,7 +334,7 @@ GEM google-cloud-location (1.3.0) gapic-common (~> 1.2) google-cloud-errors (~> 1.0) - google-cloud-translate (3.7.4) + google-cloud-translate (3.8.0) google-cloud-core (~> 1.6) google-cloud-translate-v2 (>= 0.0, < 2.a) google-cloud-translate-v3 (>= 0.11, < 2.a) @@ -344,7 +344,7 @@ GEM googleapis-common-protos (>= 1.3.10, < 2.a) googleapis-common-protos-types (>= 1.0.5, < 2.a) googleauth (>= 0.16.2, < 2.a) - google-cloud-translate-v3 (1.7.1) + google-cloud-translate-v3 (1.9.0) gapic-common (~> 1.2) google-cloud-errors (~> 1.0) google-cloud-location (~> 1.0) @@ -374,8 +374,8 @@ GEM multi_json (~> 1.11) os (>= 0.9, < 2.0) signet (>= 0.16, < 2.a) - groupdate (6.7.0) - activesupport (>= 7.1) + groupdate (6.8.0) + activesupport (>= 7.2) grpc (1.80.0) google-protobuf (>= 3.25, < 5.0) googleapis-common-protos-types (~> 1.0) @@ -395,7 +395,7 @@ GEM http-cookie (~> 1.0) http-form_data (~> 2.2) llhttp-ffi (~> 0.5.0) - http-cookie (1.1.0) + http-cookie (1.1.6) domain_name (~> 0.5) http-form_data (2.3.0) i18n (1.14.8) @@ -412,7 +412,7 @@ GEM railties (>= 6.0) responders (>= 2) io-console (0.8.2) - irb (1.17.0) + irb (1.18.0) pp (>= 0.6.0) prism (>= 1.3.0) rdoc (>= 4.0.0) @@ -421,7 +421,7 @@ GEM rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) - json (2.19.3) + json (2.19.5) jwt (3.1.2) base64 kaminari (1.2.2) @@ -472,7 +472,7 @@ GEM mime-types (3.7.0) logger mime-types-data (~> 3.2025, >= 3.2025.0507) - mime-types-data (3.2026.0317) + mime-types-data (3.2026.0414) mini_magick (5.3.1) logger mini_mime (1.1.5) @@ -480,11 +480,11 @@ GEM minitest (5.27.0) mjml-rails (4.16.0) msgpack (1.8.0) - multi_json (1.19.1) + multi_json (1.21.1) mustache (1.1.2) net-http (0.9.1) uri (>= 0.11.1) - net-imap (0.6.3) + net-imap (0.6.4) date net-protocol net-pop (0.1.2) @@ -499,12 +499,12 @@ GEM net-protocol net-ssh (7.3.2) nio4r (2.7.5) - nokogiri (1.19.2) + nokogiri (1.19.3) mini_portile2 (~> 2.8.2) racc (~> 1.4) - nokogiri (1.19.2-x86_64-linux-gnu) + nokogiri (1.19.3-x86_64-linux-gnu) racc (~> 1.4) - oj (3.16.16) + oj (3.17.0) bigdecimal (>= 3.0) ostruct (>= 0.2) oj_mimic_json (1.0.1) @@ -515,8 +515,8 @@ GEM paper_trail (17.0.0) activerecord (>= 7.1) request_store (~> 1.4) - parallel (1.27.0) - parallel_tests (5.6.0) + parallel (1.28.0) + parallel_tests (5.7.0) parallel paranoia (3.1.0) activerecord (>= 7, < 8.2) @@ -538,13 +538,13 @@ GEM puma (6.6.1) nio4r (~> 2.0) racc (1.8.1) - rack (3.2.5) + rack (3.2.6) rack-cors (3.0.0) logger rack (>= 3.0.14) rack-mini-profiler (2.3.4) rack (>= 1.2.0) - rack-session (2.1.1) + rack-session (2.1.2) base64 (>= 0.1.0) rack (>= 3.0.0) rack-test (2.2.0) @@ -583,7 +583,7 @@ GEM tsort (>= 0.2) zeitwerk (~> 2.6) rainbow (3.1.1) - rake (13.3.1) + rake (13.4.2) ransack (4.4.1) activerecord (>= 7.2) activesupport (>= 7.2) @@ -613,7 +613,7 @@ GEM redis-store (>= 1.2, < 2) redis-store (1.11.0) redis (>= 4, < 6) - regexp_parser (2.11.3) + regexp_parser (2.12.0) reline (0.6.3) io-console (~> 0.5) request_store (1.7.0) @@ -715,7 +715,7 @@ GEM logger shoulda-matchers (4.0.1) activesupport (>= 4.2.0) - sidekiq (8.1.2) + sidekiq (8.1.3) connection_pool (>= 3.0.0) json (>= 2.16.0) logger (>= 1.7.0) @@ -732,7 +732,7 @@ GEM simplecov_json_formatter (~> 0.1) simplecov-html (0.13.2) simplecov_json_formatter (0.1.4) - spring (4.4.2) + spring (4.5.0) spring-commands-rspec (1.0.4) spring (>= 0.9.1) sprockets (4.2.2) @@ -750,7 +750,7 @@ GEM net-sftp (>= 2.1.2) net-ssh (>= 2.8.0) ostruct - ssrf_filter (1.3.0) + ssrf_filter (1.5.0) standard (1.54.0) language_server-protocol (~> 3.17.0.2) lint_roller (~> 1.0) @@ -764,17 +764,17 @@ GEM lint_roller (~> 1.1) rubocop-performance (~> 1.26.0) stringio (3.2.0) - super_diff (0.18.0) - attr_extras (>= 6.2.4) - diff-lcs - patience_diff + super_diff (0.19.0) + attr_extras (>= 6.2.4, < 8) + diff-lcs (~> 1.5) + patience_diff (~> 1.2) thor (1.5.0) tilt (2.7.0) timeout (0.6.1) tsort (0.2.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - tzinfo-data (1.2026.1) + tzinfo-data (1.2026.2) tzinfo (>= 1.0.0) uglifier (4.2.1) execjs (>= 0.3.0, < 3) @@ -865,7 +865,7 @@ DEPENDENCIES letter_opener_web maxmind-geoip2 mini_magick - mjml-rails + mjml-rails (~> 4.0) nokogiri oj oj_mimic_json diff --git a/config/initializers/active_admin.rb b/config/initializers/active_admin.rb index 90fa6eb4f..68b449da2 100644 --- a/config/initializers/active_admin.rb +++ b/config/initializers/active_admin.rb @@ -143,7 +143,7 @@ # Active Admin resources and pages from here. # config.before_action do - left_sidebar!(collapsed: true) if respond_to?(:left_sidebar!) + left_sidebar!(collapsible: true, start_collapsed: false) if respond_to?(:left_sidebar!) end # Set default locale for active admin diff --git a/config/initializers/paper_trail.rb b/config/initializers/paper_trail.rb index 0579225d5..924708e95 100644 --- a/config/initializers/paper_trail.rb +++ b/config/initializers/paper_trail.rb @@ -6,3 +6,4 @@ on: %i[create update destroy] } PaperTrail.config.version_limit = nil +PaperTrail.serializer = PaperTrail::Serializers::JSON diff --git a/db/migrate/20260416100821_paper_trail_to_json.rb b/db/migrate/20260416100821_paper_trail_to_json.rb new file mode 100644 index 000000000..f27412f9b --- /dev/null +++ b/db/migrate/20260416100821_paper_trail_to_json.rb @@ -0,0 +1,11 @@ +class PaperTrailToJson < ActiveRecord::Migration[7.2] + def change + rename_column :versions, :object, :old_object + rename_column :versions, :object_changes, :old_object_changes + + change_table :versions, bulk: true do |t| + t.jsonb :object + t.jsonb :object_changes + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 9cf752bbe..e5412cbcf 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.2].define(version: 2026_03_18_192753) do +ActiveRecord::Schema[7.2].define(version: 2026_04_16_100821) do create_schema "tiger" create_schema "tiger_data" create_schema "topology" @@ -1133,10 +1133,12 @@ t.bigint "item_id", null: false t.string "event", null: false t.string "whodunnit" - t.text "object" + t.text "old_object" t.string "locale" t.datetime "created_at", precision: nil - t.text "object_changes" + t.text "old_object_changes" + t.jsonb "object" + t.jsonb "object_changes" t.index ["item_type", "item_id", "locale"], name: "index_versions_on_item_type_and_item_id_and_locale" t.index ["item_type", "item_id"], name: "index_versions_on_item_type_and_item_id" end diff --git a/lib/tasks/data_migrations.rake b/lib/tasks/data_migrations.rake index 49f74ef61..59637b7d8 100644 --- a/lib/tasks/data_migrations.rake +++ b/lib/tasks/data_migrations.rake @@ -50,4 +50,37 @@ namespace :data_migrations do end puts "Wrote tmp/data_migrations_report_mission_type_report.csv" end + + desc "Move PaperTrail versions from YAML to JSON columns." + task paper_trail_to_json: :environment do + for_real = ENV["FOR_REAL"] == "true" + batch_size = (ENV["BATCH_SIZE"] || 2000).to_i + puts "DRY RUN" unless for_real + + scope = PaperTrail::Version.all + total = scope.count + processed = 0 + errors = 0 + puts "Migrating #{total} PaperTrail versions to JSON (batch_size=#{batch_size})..." + + scope.find_in_batches(batch_size: batch_size) do |batch| + ActiveRecord::Base.transaction do + batch.each do |version| + attrs = {} + attrs[:object] = PaperTrail::Serializers::YAML.load(version.old_object) if version.old_object.present? + attrs[:object_changes] = PaperTrail::Serializers::YAML.load(version.old_object_changes) if version.old_object_changes.present? + version.update_columns(attrs) if for_real + rescue => e + errors += 1 + warn "\n Error parsing version #{version.id}: #{e.message}" + end + end + + processed += batch.size + print "\r #{processed}/#{total} (#{"%.1f" % (processed.to_f / total * 100)}%)" + end + + warn "\n #{errors} version(s) failed to parse and were skipped." if errors > 0 + puts "\nFinished migrating PaperTrail versions to JSON columns. You can now remove the old YAML columns with a separate migration." + end end