Keep bot page totals on SQLite-maintained rooms.messages_count

X-Total-Count on GET /rooms/:id/:bot_key/messages was COUNT(*) of the
room on every page. Serve it from rooms.messages_count updated by SQLite
triggers so Rails, bulk SQL, and foreign writers stay in step — without
ActiveRecord counter_cache callbacks those paths skip.

Fixes #309.

Co-authored-by: Thomas Klemm <github@tklemm.eu>
This commit is contained in:
Cursor Agent
2026-10-07 19:36:01 +00:00
parent 6e312c6028
commit 1f5858098b
9 changed files with 338 additions and 4 deletions
@@ -1,6 +1,9 @@
require "test_helper"
require "active_record/testing/query_assertions"
class Messages::ByBotsControllerTest < ActionDispatch::IntegrationTest
include ActiveRecord::Assertions::QueryAssertions
setup do
@room = rooms(:watercooler)
end
@@ -93,11 +96,14 @@ class Messages::ByBotsControllerTest < ActionDispatch::IntegrationTest
@room.messages.create!(body: "Filler #{i}", creator: users(:jason), client_message_id: "filler-#{i}")
end
get room_bot_messages_url(@room, users(:bender).bot_key)
assert_no_queries_match(/SELECT COUNT\(\*\) FROM "messages"/i) do
get room_bot_messages_url(@room, users(:bender).bot_key)
end
assert_response :success
json = JSON.parse(response.body)
assert_equal Message::PAGE_SIZE, json.size
assert_equal @room.reload.messages_count.to_s, response.headers["X-Total-Count"]
assert_equal "41", response.headers["X-Total-Count"]
assert_not_includes json.map { it["id"] }, messages(:fourth).id
@@ -119,7 +125,10 @@ class Messages::ByBotsControllerTest < ActionDispatch::IntegrationTest
end
test "index in a room with no messages" do
get room_bot_messages_url(rooms(:bender_and_kevin), users(:bender).bot_key)
room = rooms(:bender_and_kevin)
assert_equal 0, room.messages_count
get room_bot_messages_url(room, users(:bender).bot_key)
assert_response :success
assert_equal [], JSON.parse(response.body)