Give a video a poster only once its poster variant is made

ActiveStorage::Preview#processed? is true as soon as ffmpeg's frame is attached, but the poster is a
variant of that frame and can fail on its own: the POST rescues a Vips::Error and leaves the frame
attached. The view then emitted the poster's URL, and every view retried the resize. It now checks the
variant too, from the variant records with_attached_attachment already preloads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bj8KnxpTf9sj2Ysa8aLAVa
This commit is contained in:
Marcello Costagliola
2026-10-06 15:34:46 +02:00
parent 9912e63d69
commit 5f198146e8
2 changed files with 13 additions and 1 deletions
@@ -40,9 +40,10 @@ class Messages::AttachmentPresentation
end
end
# A preview is processed once the frame is drawn, but the poster is a variant of that frame, which can fail on its own.
def video_poster_url
poster = message.attachment.preview(:poster)
url_for(poster) if poster.processed?
url_for(poster) if poster.processed? && poster.image.variant(poster.variation).processed?
end
def lightboxed_image_preview_tag
+11
View File
@@ -51,6 +51,17 @@ class MessagesHelperTest < ActionView::TestCase
assert_no_match %r{poster=|/representations/}, presentation
end
test "message_presentation shows a video whose frame was drawn but whose poster wasn't made without one" do
message = attachment_message("alpha-centuri.mov", "video/quicktime", processed: false)
message.attachment.preview(format: :jpg).processed
assert message.attachment.preview(:poster).processed?
presentation = view.message_presentation(message.reload)
assert_match %r{<video[^>]+src="[^"]*alpha-centuri\.mov"}, presentation
assert_no_match %r{poster=|/representations/}, presentation
end
private
def attachment_message(file, content_type, processed:)
attributes = { creator: users(:jason), client_message_id: "0015", attachment: fixture_file_upload(file, content_type) }