From 5f198146e85ecfaa44c6050a010cee7281a6ace7 Mon Sep 17 00:00:00 2001 From: Marcello Costagliola Date: Tue, 6 Oct 2026 15:34:46 +0200 Subject: [PATCH] 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 Claude-Session: https://claude.ai/code/session_01Bj8KnxpTf9sj2Ysa8aLAVa --- app/helpers/messages/attachment_presentation.rb | 3 ++- test/helpers/messages_helper_test.rb | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/app/helpers/messages/attachment_presentation.rb b/app/helpers/messages/attachment_presentation.rb index 82ce92d..eec9a3b 100644 --- a/app/helpers/messages/attachment_presentation.rb +++ b/app/helpers/messages/attachment_presentation.rb @@ -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 diff --git a/test/helpers/messages_helper_test.rb b/test/helpers/messages_helper_test.rb index f648827..488d72a 100644 --- a/test/helpers/messages_helper_test.rb +++ b/test/helpers/messages_helper_test.rb @@ -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{]+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) }