Fix ActiveStorage FileNotFoundError with immediate variant processing (#2022)

When ActiveStorage::Record uses `connects_to` for read replica support,
it creates a separate connection pool from ApplicationRecord. This causes
`after_commit` callbacks to fire in non-deterministic order - the
Attachment's `create_variants` callback can fire before the User model's
upload callback completes, resulting in FileNotFoundError.

The fix removes replica connection configuration from ActiveStorage::Record
so it shares the same connection pool as application models, ensuring
proper callback ordering.

Also reverts test workarounds that were added to work around this issue,
since the root cause is now fixed.

See: https://github.com/rails/rails/issues/53694
This commit is contained in:
Jeremy Daer
2025-12-08 14:44:49 -08:00
committed by GitHub
parent cb0e9b9962
commit 49c4f2adc6
5 changed files with 19 additions and 31 deletions
@@ -27,9 +27,7 @@ class Users::AvatarsControllerTest < ActionDispatch::IntegrationTest
end
test "show own image redirects to the blob url" do
# Create blob separately to ensure file is uploaded before variant processing
blob = ActiveStorage::Blob.create_and_upload!(io: File.open(file_fixture("moon.jpg")), filename: "moon.jpg", content_type: "image/jpeg")
users(:david).avatar.attach(blob)
users(:david).avatar.attach(io: File.open(file_fixture("moon.jpg")), filename: "moon.jpg", content_type: "image/jpeg")
assert users(:david).avatar.attached?
get user_avatar_path(users(:david))
@@ -38,9 +36,7 @@ class Users::AvatarsControllerTest < ActionDispatch::IntegrationTest
end
test "show other image redirects to the blob url" do
# Create blob separately to ensure file is uploaded before variant processing
blob = ActiveStorage::Blob.create_and_upload!(io: File.open(file_fixture("moon.jpg")), filename: "moon.jpg", content_type: "image/jpeg")
users(:kevin).avatar.attach(blob)
users(:kevin).avatar.attach(io: File.open(file_fixture("moon.jpg")), filename: "moon.jpg", content_type: "image/jpeg")
assert users(:kevin).avatar.attached?
get user_avatar_path(users(:kevin))
+2 -3
View File
@@ -79,10 +79,9 @@ class UsersControllerTest < ActionDispatch::IntegrationTest
test "update with valid avatar" do
sign_in_as :kevin
# Create blob separately to ensure file is uploaded before variant processing
blob = ActiveStorage::Blob.create_and_upload!(io: File.open(file_fixture("avatar.png")), filename: "avatar.png", content_type: "image/png")
png_file = fixture_file_upload("avatar.png", "image/png")
put user_path(users(:kevin)), params: { user: { avatar: blob.signed_id } }
put user_path(users(:kevin)), params: { user: { avatar: png_file } }
assert_redirected_to user_path(users(:kevin))
assert users(:kevin).reload.avatar.attached?
assert_equal "image/png", users(:kevin).avatar.content_type