From d8ed2f44b88ed56ba41674d58029ba0ba76499fd Mon Sep 17 00:00:00 2001 From: "Stanko K.R." Date: Tue, 24 Feb 2026 07:36:20 +0100 Subject: [PATCH 1/6] Reconcile card count after import --- app/models/account/data_transfer/account_record_set.rb | 2 +- app/models/account/import.rb | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/models/account/data_transfer/account_record_set.rb b/app/models/account/data_transfer/account_record_set.rb index b7869eb73..a5151f05f 100644 --- a/app/models/account/data_transfer/account_record_set.rb +++ b/app/models/account/data_transfer/account_record_set.rb @@ -31,7 +31,7 @@ class Account::DataTransfer::AccountRecordSet < Account::DataTransfer::RecordSet account_data = load(files.first) join_code_data = account_data.delete("join_code") - account.update!(name: account_data.fetch("name")) + account.update!(name: account_data.fetch("name"), cards_count: account_data.fetch("cards_count", 0)) account.join_code.update!(join_code_data.slice("usage_count", "usage_limit")) account.join_code.update(code: join_code_data.fetch("code")) end diff --git a/app/models/account/import.rb b/app/models/account/import.rb index 14ee376ea..50ec3769d 100644 --- a/app/models/account/import.rb +++ b/app/models/account/import.rb @@ -48,6 +48,7 @@ class Account::Import < ApplicationRecord end add_importer_to_all_access_boards + reconcile_cards_count reconcile_account_storage mark_completed @@ -78,6 +79,10 @@ class Account::Import < ApplicationRecord ImportMailer.failed(self).deliver_later end + def reconcile_cards_count + account.update_column :cards_count, [ account.cards_count, account.cards.maximum(:number).to_i ].max + end + def add_importer_to_all_access_boards importer = account.users.find_by!(identity: identity) From 55779f8ac47a9e44a173d1a6a29266cd3d3a0ac5 Mon Sep 17 00:00:00 2001 From: "Stanko K.R." Date: Tue, 24 Feb 2026 07:36:51 +0100 Subject: [PATCH 2/6] Organize the record sets better --- .../rich_text_record_set.rb} | 10 +++++----- .../blob_record_set.rb} | 8 ++++---- .../file_record_set.rb} | 10 +++++----- app/models/account/data_transfer/manifest.rb | 6 +++--- .../rich_text_record_set_test.rb} | 10 +++++----- 5 files changed, 22 insertions(+), 22 deletions(-) rename app/models/account/data_transfer/{action_text_rich_text_record_set.rb => action_text/rich_text_record_set.rb} (86%) rename app/models/account/data_transfer/{active_storage_blob_record_set.rb => active_storage/blob_record_set.rb} (55%) rename app/models/account/data_transfer/{blob_file_record_set.rb => active_storage/file_record_set.rb} (72%) rename test/models/account/data_transfer/{action_text_rich_text_record_set_test.rb => action_text/rich_text_record_set_test.rb} (86%) diff --git a/app/models/account/data_transfer/action_text_rich_text_record_set.rb b/app/models/account/data_transfer/action_text/rich_text_record_set.rb similarity index 86% rename from app/models/account/data_transfer/action_text_rich_text_record_set.rb rename to app/models/account/data_transfer/action_text/rich_text_record_set.rb index fa1a23cb9..d56a12dc1 100644 --- a/app/models/account/data_transfer/action_text_rich_text_record_set.rb +++ b/app/models/account/data_transfer/action_text/rich_text_record_set.rb @@ -1,4 +1,4 @@ -class Account::DataTransfer::ActionTextRichTextRecordSet < Account::DataTransfer::RecordSet +class Account::DataTransfer::ActionText::RichTextRecordSet < Account::DataTransfer::RecordSet ATTRIBUTES = %w[ account_id body @@ -11,12 +11,12 @@ class Account::DataTransfer::ActionTextRichTextRecordSet < Account::DataTransfer ].freeze def initialize(account) - super(account: account, model: ActionText::RichText) + super(account: account, model: ::ActionText::RichText) end private def records - ActionText::RichText.where(account: account) + ::ActionText::RichText.where(account: account) end def export_record(rich_text) @@ -35,7 +35,7 @@ class Account::DataTransfer::ActionTextRichTextRecordSet < Account::DataTransfer data.slice(*ATTRIBUTES).merge("account_id" => account.id) end - ActionText::RichText.insert_all!(batch_data) + ::ActionText::RichText.insert_all!(batch_data) end def check_record(file_path) @@ -58,7 +58,7 @@ class Account::DataTransfer::ActionTextRichTextRecordSet < Account::DataTransfer return nil if content.blank? content.send(:attachment_nodes).each do |node| - sgid = SignedGlobalID.parse(node["sgid"], for: ActionText::Attachable::LOCATOR_NAME) + sgid = SignedGlobalID.parse(node["sgid"], for: ::ActionText::Attachable::LOCATOR_NAME) record = begin sgid&.find diff --git a/app/models/account/data_transfer/active_storage_blob_record_set.rb b/app/models/account/data_transfer/active_storage/blob_record_set.rb similarity index 55% rename from app/models/account/data_transfer/active_storage_blob_record_set.rb rename to app/models/account/data_transfer/active_storage/blob_record_set.rb index 10ee326ad..1637768f3 100644 --- a/app/models/account/data_transfer/active_storage_blob_record_set.rb +++ b/app/models/account/data_transfer/active_storage/blob_record_set.rb @@ -1,9 +1,9 @@ -class Account::DataTransfer::ActiveStorageBlobRecordSet < Account::DataTransfer::RecordSet +class Account::DataTransfer::ActiveStorage::BlobRecordSet < Account::DataTransfer::RecordSet def initialize(account) super( account: account, - model: ActiveStorage::Blob, - attributes: ActiveStorage::Blob.column_names - %w[service_name] + model: ::ActiveStorage::Blob, + attributes: ::ActiveStorage::Blob.column_names - %w[service_name] ) end @@ -13,7 +13,7 @@ class Account::DataTransfer::ActiveStorageBlobRecordSet < Account::DataTransfer: data = load(file) data.slice(*attributes).merge( "account_id" => account.id, - "service_name" => ActiveStorage::Blob.service.name + "service_name" => ::ActiveStorage::Blob.service.name ) end diff --git a/app/models/account/data_transfer/blob_file_record_set.rb b/app/models/account/data_transfer/active_storage/file_record_set.rb similarity index 72% rename from app/models/account/data_transfer/blob_file_record_set.rb rename to app/models/account/data_transfer/active_storage/file_record_set.rb index 4bbfcba10..15d359353 100644 --- a/app/models/account/data_transfer/blob_file_record_set.rb +++ b/app/models/account/data_transfer/active_storage/file_record_set.rb @@ -1,11 +1,11 @@ -class Account::DataTransfer::BlobFileRecordSet < Account::DataTransfer::RecordSet +class Account::DataTransfer::ActiveStorage::FileRecordSet < Account::DataTransfer::RecordSet def initialize(account) - super(account: account, model: ActiveStorage::Blob) + super(account: account, model: ::ActiveStorage::Blob) end private def records - ActiveStorage::Blob.where(account: account) + ::ActiveStorage::Blob.where(account: account) end def export_record(blob) @@ -23,7 +23,7 @@ class Account::DataTransfer::BlobFileRecordSet < Account::DataTransfer::RecordSe def import_batch(files) files.each do |file| key = File.basename(file) - blob = ActiveStorage::Blob.find_by(key: key, account: account) + blob = ::ActiveStorage::Blob.find_by(key: key, account: account) next unless blob zip.read(file) do |stream| @@ -35,7 +35,7 @@ class Account::DataTransfer::BlobFileRecordSet < Account::DataTransfer::RecordSe def check_record(file_path) key = File.basename(file_path) - unless zip.exists?("data/active_storage_blobs/#{key}.json") || ActiveStorage::Blob.exists?(key: key, account: account) + unless zip.exists?("data/active_storage_blobs/#{key}.json") || ::ActiveStorage::Blob.exists?(key: key, account: account) # File exists without corresponding blob record - could be orphaned or blob not yet imported # We allow this since blob metadata is imported before files end diff --git a/app/models/account/data_transfer/manifest.rb b/app/models/account/data_transfer/manifest.rb index b5976e3d5..2159926d5 100644 --- a/app/models/account/data_transfer/manifest.rb +++ b/app/models/account/data_transfer/manifest.rb @@ -35,10 +35,10 @@ class Account::DataTransfer::Manifest ::Filter, ::Webhook::DelinquencyTracker, ::Event, ::Notification, ::Notification::Bundle, ::Webhook::Delivery ), - Account::DataTransfer::ActiveStorageBlobRecordSet.new(account), + Account::DataTransfer::ActiveStorage::BlobRecordSet.new(account), *build_record_sets(::ActiveStorage::Attachment), - Account::DataTransfer::ActionTextRichTextRecordSet.new(account), - Account::DataTransfer::BlobFileRecordSet.new(account) + Account::DataTransfer::ActionText::RichTextRecordSet.new(account), + Account::DataTransfer::ActiveStorage::FileRecordSet.new(account) ] end diff --git a/test/models/account/data_transfer/action_text_rich_text_record_set_test.rb b/test/models/account/data_transfer/action_text/rich_text_record_set_test.rb similarity index 86% rename from test/models/account/data_transfer/action_text_rich_text_record_set_test.rb rename to test/models/account/data_transfer/action_text/rich_text_record_set_test.rb index 14a7aeb9c..08e0b5610 100644 --- a/test/models/account/data_transfer/action_text_rich_text_record_set_test.rb +++ b/test/models/account/data_transfer/action_text/rich_text_record_set_test.rb @@ -1,6 +1,6 @@ require "test_helper" -class Account::DataTransfer::ActionTextRichTextRecordSetTest < ActiveSupport::TestCase +class Account::DataTransfer::ActionText::RichTextRecordSetTest < ActiveSupport::TestCase test "check rejects ActionText record referencing existing card in another account" do importing_account = Account.create!(name: "Importing Account", external_account_id: 99999999) @@ -29,7 +29,7 @@ class Account::DataTransfer::ActionTextRichTextRecordSetTest < ActiveSupport::Te reader = ZipFile::Reader.new(tempfile) - record_set = Account::DataTransfer::ActionTextRichTextRecordSet.new(importing_account) + record_set = Account::DataTransfer::ActionText::RichTextRecordSet.new(importing_account) error = assert_raises(Account::DataTransfer::RecordSet::IntegrityError) do record_set.check(from: reader) @@ -50,7 +50,7 @@ class Account::DataTransfer::ActionTextRichTextRecordSetTest < ActiveSupport::Te cross_tenant_gid = victim_tag.to_global_id.to_s html = %() - record_set = Account::DataTransfer::ActionTextRichTextRecordSet.new(attacker_account) + record_set = Account::DataTransfer::ActionText::RichTextRecordSet.new(attacker_account) result = record_set.send(:convert_gids_to_sgids, html) assert_no_match(/sgid=/, result, "Cross-tenant GID must not be converted to SGID") @@ -65,7 +65,7 @@ class Account::DataTransfer::ActionTextRichTextRecordSetTest < ActiveSupport::Te same_account_gid = own_tag.to_global_id.to_s html = %() - record_set = Account::DataTransfer::ActionTextRichTextRecordSet.new(own_account) + record_set = Account::DataTransfer::ActionText::RichTextRecordSet.new(own_account) result = record_set.send(:convert_gids_to_sgids, html) assert_match(/sgid=/, result, "Same-account GID should be converted to SGID") @@ -76,7 +76,7 @@ class Account::DataTransfer::ActionTextRichTextRecordSetTest < ActiveSupport::Te nonexistent_gid = "gid://fizzy/Tag/00000000000000000000000000" html = %() - record_set = Account::DataTransfer::ActionTextRichTextRecordSet.new(accounts(:"37s")) + record_set = Account::DataTransfer::ActionText::RichTextRecordSet.new(accounts(:"37s")) result = record_set.send(:convert_gids_to_sgids, html) assert_no_match(/sgid=/, result, "Non-existent record should not produce SGID") From 4eadce8ffe5a3167ae4625d954a10d9871f9c97f Mon Sep 17 00:00:00 2001 From: "Stanko K.R." Date: Tue, 24 Feb 2026 08:11:47 +0100 Subject: [PATCH 3/6] Automatically update account slugs in links --- .../action_text/rich_text_record_set.rb | 29 +++++++++-- .../action_text/rich_text_record_set_test.rb | 48 ++++++++++++++++--- test/models/account/import_test.rb | 30 ++++++++++++ 3 files changed, 96 insertions(+), 11 deletions(-) diff --git a/app/models/account/data_transfer/action_text/rich_text_record_set.rb b/app/models/account/data_transfer/action_text/rich_text_record_set.rb index d56a12dc1..e29abd011 100644 --- a/app/models/account/data_transfer/action_text/rich_text_record_set.rb +++ b/app/models/account/data_transfer/action_text/rich_text_record_set.rb @@ -31,7 +31,7 @@ class Account::DataTransfer::ActionText::RichTextRecordSet < Account::DataTransf def import_batch(files) batch_data = files.map do |file| data = load(file) - data["body"] = convert_gids_to_sgids(data["body"]) + data["body"] = transform_body_for_import(data["body"]) data.slice(*ATTRIBUTES).merge("account_id" => account.id) end @@ -75,11 +75,16 @@ class Account::DataTransfer::ActionText::RichTextRecordSet < Account::DataTransf content.fragment.source.to_html end - def convert_gids_to_sgids(html) - return html if html.blank? + def transform_body_for_import(body) + return body if body.blank? - fragment = Nokogiri::HTML.fragment(html) + Nokogiri::HTML.fragment(body) + .then { convert_gids_to_sgids(it) } + .then { replace_account_slugs(it) } + .to_html + end + def convert_gids_to_sgids(fragment) fragment.css("action-text-attachment[gid]").each do |node| gid = GlobalID.parse(node["gid"]) @@ -97,6 +102,20 @@ class Account::DataTransfer::ActionText::RichTextRecordSet < Account::DataTransf end end - fragment.to_html + fragment + end + + def replace_account_slugs(fragment) + fragment.css("a[href]").each do |link| + match = link["href"].match(AccountSlug::PATH_INFO_MATCH) + + if match + path = match.post_match.presence || "/" + valid_path = Rails.application.routes.recognize_path(path) rescue nil + link["href"] = "#{account.slug}#{remaining_path}" if valid_path + end + end + + fragment end end diff --git a/test/models/account/data_transfer/action_text/rich_text_record_set_test.rb b/test/models/account/data_transfer/action_text/rich_text_record_set_test.rb index 08e0b5610..bee51869c 100644 --- a/test/models/account/data_transfer/action_text/rich_text_record_set_test.rb +++ b/test/models/account/data_transfer/action_text/rich_text_record_set_test.rb @@ -42,7 +42,7 @@ class Account::DataTransfer::ActionText::RichTextRecordSetTest < ActiveSupport:: importing_account&.destroy end - test "convert_gids_to_sgids skips GIDs belonging to another account" do + test "transform_body_for_import skips GIDs belonging to another account" do victim_tag = tags(:web) attacker_account = accounts(:initech) assert_not_equal attacker_account.id, victim_tag.account_id @@ -51,13 +51,13 @@ class Account::DataTransfer::ActionText::RichTextRecordSetTest < ActiveSupport:: html = %() record_set = Account::DataTransfer::ActionText::RichTextRecordSet.new(attacker_account) - result = record_set.send(:convert_gids_to_sgids, html) + result = record_set.send(:transform_body_for_import, html) assert_no_match(/sgid=/, result, "Cross-tenant GID must not be converted to SGID") assert_match(/gid=/, result, "Original GID should remain unconverted") end - test "convert_gids_to_sgids converts GIDs belonging to the same account" do + test "transform_body_for_import converts GIDs belonging to the same account" do own_tag = tags(:web) own_account = accounts(:"37s") assert_equal own_account.id, own_tag.account_id @@ -66,19 +66,55 @@ class Account::DataTransfer::ActionText::RichTextRecordSetTest < ActiveSupport:: html = %() record_set = Account::DataTransfer::ActionText::RichTextRecordSet.new(own_account) - result = record_set.send(:convert_gids_to_sgids, html) + result = record_set.send(:transform_body_for_import, html) assert_match(/sgid=/, result, "Same-account GID should be converted to SGID") assert_no_match(/ gid=/, result, "GID should be removed after SGID conversion") end - test "convert_gids_to_sgids handles non-existent record GIDs gracefully" do + test "transform_body_for_import handles non-existent record GIDs gracefully" do nonexistent_gid = "gid://fizzy/Tag/00000000000000000000000000" html = %() record_set = Account::DataTransfer::ActionText::RichTextRecordSet.new(accounts(:"37s")) - result = record_set.send(:convert_gids_to_sgids, html) + result = record_set.send(:transform_body_for_import, html) assert_no_match(/sgid=/, result, "Non-existent record should not produce SGID") end + + test "replace_account_slugs rewrites relative URLs with account slug" do + target_account = accounts(:"37s") + source_slug = "9999999" + target_slug = AccountSlug.encode(target_account.external_account_id) + + html = %(

See card 42

) + + record_set = Account::DataTransfer::ActionText::RichTextRecordSet.new(target_account) + result = record_set.send(:transform_body_for_import, html) + + assert_includes result, "/#{target_slug}/cards/42" + assert_not_includes result, source_slug + end + + test "replace_account_slugs leaves absolute URLs alone" do + target_account = accounts(:"37s") + + html = %(

See board

) + + record_set = Account::DataTransfer::ActionText::RichTextRecordSet.new(target_account) + result = record_set.send(:transform_body_for_import, html) + + assert_includes result, "https://fizzy.app/9999999/boards/7" + end + + test "replace_account_slugs leaves plain text alone" do + target_account = accounts(:"37s") + + html = "

Nothing to rewrite here

" + + record_set = Account::DataTransfer::ActionText::RichTextRecordSet.new(target_account) + result = record_set.send(:transform_body_for_import, html) + + assert_equal html, result + end end diff --git a/test/models/account/import_test.rb b/test/models/account/import_test.rb index a33cc32c2..7bf407041 100644 --- a/test/models/account/import_test.rb +++ b/test/models/account/import_test.rb @@ -62,6 +62,36 @@ class Account::ImportTest < ActiveSupport::TestCase export_tempfile&.unlink end + test "import reconciles cards count so new cards get correct numbers" do + source_account = accounts("37s") + exporter = users(:david) + identity = exporter.identity + max_card_number = source_account.cards.maximum(:number) + + export = Account::Export.create!(account: source_account, user: exporter) + export.build + + export_tempfile = Tempfile.new([ "export", ".zip" ]) + export.file.open { |f| FileUtils.cp(f.path, export_tempfile.path) } + + source_account.destroy! + + target_account = Account.create_with_owner(account: { name: "Import Test" }, owner: { identity: identity, name: exporter.name }) + import = Account::Import.create!(identity: identity, account: target_account) + Current.set(account: target_account) do + import.file.attach(io: File.open(export_tempfile.path), filename: "export.zip", content_type: "application/zip") + end + + import.check + import.process + + target_account.reload + assert_operator target_account.cards_count, :>=, max_card_number + ensure + export_tempfile&.close + export_tempfile&.unlink + end + test "check sets no failure_reason for unexpected errors" do import = Account::Import.create!(identity: identities(:david), account: Account.create!(name: "Import Test")) From 2f9d4533c582d4c575def9e2dbfe9eabe4b1f54c Mon Sep 17 00:00:00 2001 From: "Stanko K.R." Date: Tue, 24 Feb 2026 08:22:01 +0100 Subject: [PATCH 4/6] Relativize absolute links to the instance on export --- .../action_text/rich_text_record_set.rb | 30 +++++++++-- .../action_text/rich_text_record_set_test.rb | 53 +++++++++++++++++++ 2 files changed, 80 insertions(+), 3 deletions(-) diff --git a/app/models/account/data_transfer/action_text/rich_text_record_set.rb b/app/models/account/data_transfer/action_text/rich_text_record_set.rb index e29abd011..01e046dbe 100644 --- a/app/models/account/data_transfer/action_text/rich_text_record_set.rb +++ b/app/models/account/data_transfer/action_text/rich_text_record_set.rb @@ -20,7 +20,7 @@ class Account::DataTransfer::ActionText::RichTextRecordSet < Account::DataTransf end def export_record(rich_text) - data = rich_text.as_json.merge("body" => convert_sgids_to_gids(rich_text.body)) + data = rich_text.as_json.merge("body" => transform_body_for_export(rich_text.body)) zip.add_file "data/action_text_rich_texts/#{rich_text.id}.json", data.to_json end @@ -54,9 +54,14 @@ class Account::DataTransfer::ActionText::RichTextRecordSet < Account::DataTransf check_associations_dont_exist(data) end - def convert_sgids_to_gids(content) + def transform_body_for_export(content) return nil if content.blank? + html = convert_sgids_to_gids(content) + relativize_urls(html) + end + + def convert_sgids_to_gids(content) content.send(:attachment_nodes).each do |node| sgid = SignedGlobalID.parse(node["sgid"], for: ::ActionText::Attachable::LOCATOR_NAME) @@ -75,6 +80,25 @@ class Account::DataTransfer::ActionText::RichTextRecordSet < Account::DataTransf content.fragment.source.to_html end + def relativize_urls(html) + host = Rails.application.routes.default_url_options[:host] + return html unless host + + fragment = Nokogiri::HTML.fragment(html) + + fragment.css("a[href]").each do |link| + uri = URI.parse(link["href"]) rescue nil + + if uri.respond_to?(:host) && uri.host == host + link["href"] = uri.path + link["href"] += "?#{uri.query}" if uri.query + link["href"] += "##{uri.fragment}" if uri.fragment + end + end + + fragment.to_html + end + def transform_body_for_import(body) return body if body.blank? @@ -112,7 +136,7 @@ class Account::DataTransfer::ActionText::RichTextRecordSet < Account::DataTransf if match path = match.post_match.presence || "/" valid_path = Rails.application.routes.recognize_path(path) rescue nil - link["href"] = "#{account.slug}#{remaining_path}" if valid_path + link["href"] = "#{account.slug}#{path}" if valid_path end end diff --git a/test/models/account/data_transfer/action_text/rich_text_record_set_test.rb b/test/models/account/data_transfer/action_text/rich_text_record_set_test.rb index bee51869c..3fed8126d 100644 --- a/test/models/account/data_transfer/action_text/rich_text_record_set_test.rb +++ b/test/models/account/data_transfer/action_text/rich_text_record_set_test.rb @@ -117,4 +117,57 @@ class Account::DataTransfer::ActionText::RichTextRecordSetTest < ActiveSupport:: assert_equal html, result end + + test "relativize_urls strips instance host from absolute URLs" do + with_default_url_host("fizzy.example.com") do + record_set = Account::DataTransfer::ActionText::RichTextRecordSet.new(accounts(:"37s")) + + html = %(

See card

) + result = record_set.send(:relativize_urls, html) + + assert_includes result, %(/123/cards/42) + assert_not_includes result, "fizzy.example.com" + end + end + + test "relativize_urls preserves query and fragment" do + with_default_url_host("fizzy.example.com") do + record_set = Account::DataTransfer::ActionText::RichTextRecordSet.new(accounts(:"37s")) + + html = %(

link

) + result = record_set.send(:relativize_urls, html) + + assert_includes result, "/123/cards/42?tab=comments#comment_1" + assert_not_includes result, "fizzy.example.com" + end + end + + test "relativize_urls leaves external URLs alone" do + with_default_url_host("fizzy.example.com") do + record_set = Account::DataTransfer::ActionText::RichTextRecordSet.new(accounts(:"37s")) + + html = %(

link

) + result = record_set.send(:relativize_urls, html) + + assert_includes result, "https://github.com/some/repo" + end + end + + test "relativize_urls is a no-op when host is not configured" do + record_set = Account::DataTransfer::ActionText::RichTextRecordSet.new(accounts(:"37s")) + + html = %(

link

) + result = record_set.send(:relativize_urls, html) + + assert_includes result, "https://fizzy.example.com/123/cards/42" + end + + private + def with_default_url_host(host) + original = Rails.application.routes.default_url_options[:host] + Rails.application.routes.default_url_options[:host] = host + yield + ensure + Rails.application.routes.default_url_options[:host] = original + end end From 66fdcae9603e5ede40401b1449dfeb3e41ba4149 Mon Sep 17 00:00:00 2001 From: "Stanko K.R." Date: Tue, 24 Feb 2026 08:28:52 +0100 Subject: [PATCH 5/6] Fix CI failure with no host set --- .../action_text/rich_text_record_set_test.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/models/account/data_transfer/action_text/rich_text_record_set_test.rb b/test/models/account/data_transfer/action_text/rich_text_record_set_test.rb index 3fed8126d..05d4e0e6c 100644 --- a/test/models/account/data_transfer/action_text/rich_text_record_set_test.rb +++ b/test/models/account/data_transfer/action_text/rich_text_record_set_test.rb @@ -154,12 +154,14 @@ class Account::DataTransfer::ActionText::RichTextRecordSetTest < ActiveSupport:: end test "relativize_urls is a no-op when host is not configured" do - record_set = Account::DataTransfer::ActionText::RichTextRecordSet.new(accounts(:"37s")) + with_default_url_host(nil) do + record_set = Account::DataTransfer::ActionText::RichTextRecordSet.new(accounts(:"37s")) - html = %(

link

) - result = record_set.send(:relativize_urls, html) + html = %(

link

) + result = record_set.send(:relativize_urls, html) - assert_includes result, "https://fizzy.example.com/123/cards/42" + assert_includes result, "https://fizzy.example.com/123/cards/42" + end end private From 0648583289c77df784cbd4ef0f9a5526d0261d96 Mon Sep 17 00:00:00 2001 From: "Stanko K.R." Date: Tue, 24 Feb 2026 08:35:11 +0100 Subject: [PATCH 6/6] Fix other test failures caused by default host manipulation --- .../action_text/rich_text_record_set_test.rb | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/test/models/account/data_transfer/action_text/rich_text_record_set_test.rb b/test/models/account/data_transfer/action_text/rich_text_record_set_test.rb index 05d4e0e6c..a28935a3e 100644 --- a/test/models/account/data_transfer/action_text/rich_text_record_set_test.rb +++ b/test/models/account/data_transfer/action_text/rich_text_record_set_test.rb @@ -166,10 +166,16 @@ class Account::DataTransfer::ActionText::RichTextRecordSetTest < ActiveSupport:: private def with_default_url_host(host) - original = Rails.application.routes.default_url_options[:host] - Rails.application.routes.default_url_options[:host] = host + options = Rails.application.routes.default_url_options + had_key = options.key?(:host) + original = options[:host] + options[:host] = host yield ensure - Rails.application.routes.default_url_options[:host] = original + if had_key + options[:host] = original + else + options.delete(:host) + end end end