From 468fe5f16b4c40bcb31803fcfe5d183f4fea6c28 Mon Sep 17 00:00:00 2001 From: Kevin McConnell Date: Wed, 21 Jan 2026 09:42:44 +0000 Subject: [PATCH] Only index up to 32KB of search content To prevent overflowing the columns in the search index tables (and also just to avoid creating massive indexes), let's limit the searchable content to the first 32KB. --- app/models/concerns/searchable.rb | 8 +++++++- test/models/card/searchable_test.rb | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/app/models/concerns/searchable.rb b/app/models/concerns/searchable.rb index 8b39504ef..17d1f186a 100644 --- a/app/models/concerns/searchable.rb +++ b/app/models/concerns/searchable.rb @@ -1,6 +1,8 @@ module Searchable extend ActiveSupport::Concern + SEARCH_CONTENT_LIMIT = 32.kilobytes + included do after_create_commit :create_in_search_index after_update_commit :update_in_search_index @@ -32,11 +34,15 @@ module Searchable card_id: search_card_id, board_id: search_board_id, title: search_title, - content: search_content, + content: search_record_content, created_at: created_at } end + def search_record_content + search_content&.truncate_bytes(SEARCH_CONTENT_LIMIT, omission: "") + end + def search_record_class Search::Record.for(account_id) end diff --git a/test/models/card/searchable_test.rb b/test/models/card/searchable_test.rb index d6dcdf60c..5c7ca9c86 100644 --- a/test/models/card/searchable_test.rb +++ b/test/models/card/searchable_test.rb @@ -32,6 +32,24 @@ class Card::SearchableTest < ActiveSupport::TestCase assert_not_includes results, card_in_other_board end + test "search content is truncated to a reasonable limit" do + search_record_class = Search::Record.for(@user.account_id) + + # Create a card with unreasonably long content + long_content = "asdf " * Searchable::SEARCH_CONTENT_LIMIT + card = @board.cards.create!(title: "Card with long description", creator: @user) + card.description = ActionText::Content.new(long_content) + card.save! + + # Check if was indexed + results = Card.mentioning("asdf", user: @user) + assert_includes results, card + + # Check the content length was within the limit + search_record = search_record_class.find_by(searchable_type: "Card", searchable_id: card.id) + assert search_record.content.bytesize <= Searchable::SEARCH_CONTENT_LIMIT + end + test "deleting card removes search record and FTS entry" do search_record_class = Search::Record.for(@user.account_id) card = @board.cards.create!(title: "Card to delete", creator: @user)