diff --git a/activestorage/app/jobs/active_storage/preview_image_job.rb b/activestorage/app/jobs/active_storage/preview_image_job.rb new file mode 100644 index 0000000000..25ee52c1f5 --- /dev/null +++ b/activestorage/app/jobs/active_storage/preview_image_job.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class ActiveStorage::PreviewImageJob < ActiveStorage::BaseJob + queue_as { ActiveStorage.queues[:preview_image] } + + discard_on ActiveRecord::RecordNotFound, ActiveStorage::UnrepresentableError + retry_on ActiveStorage::IntegrityError, attempts: 10, wait: :polynomially_longer + + def perform(blob, variations) + blob.preview({}).processed + + variations.each do |transformations| + blob.preprocessed(transformations) + end + end +end diff --git a/activestorage/app/models/active_storage/attachment.rb b/activestorage/app/models/active_storage/attachment.rb index 8cfd7e38db..ce439f6fd2 100644 --- a/activestorage/app/models/active_storage/attachment.rb +++ b/activestorage/app/models/active_storage/attachment.rb @@ -132,8 +132,18 @@ def mirror_blob_later end def transform_variants_later - named_variants.each do |_name, named_variant| - blob.preprocessed(named_variant.transformations) if named_variant.preprocessed?(record) + preprocessed_variations = named_variants.filter_map { |_name, named_variant| + if named_variant.preprocessed?(record) + named_variant.transformations + end + } + + if blob.preview_image_needed_before_processing_variants? + blob.create_preview_image_later(preprocessed_variations) + else + preprocessed_variations.each do |transformations| + blob.preprocessed(transformations) + end end end diff --git a/activestorage/app/models/active_storage/blob/representable.rb b/activestorage/app/models/active_storage/blob/representable.rb index efa74eea33..5d8783d077 100644 --- a/activestorage/app/models/active_storage/blob/representable.rb +++ b/activestorage/app/models/active_storage/blob/representable.rb @@ -98,6 +98,14 @@ def representable? variable? || previewable? end + def preview_image_needed_before_processing_variants? + previewable? && !preview_image.attached? + end + + def create_preview_image_later(variations) + ActiveStorage::PreviewImageJob.perform_later(self, variations) if representable? + end + def preprocessed(transformations) # :nodoc: ActiveStorage::TransformJob.perform_later(self, transformations) if representable? end