Derivatives seems to be losing the uploaded file

This feature was working once, and I just got alerted by the client that it has stopped working. As far as I can tell, nothing has changed in this code in quite a while, so I’m confused whether it ever worked, or something changed.

Here’s an attempt to upload an image:

Started POST "/ckeditor/pictures?&responseType=json" for 173.161.197.6 at 2020-09-22 19:07:28 +0000
Processing by Ckeditor::PicturesController#create as */*
  Parameters: {"upload"=>#<ActionDispatch::Http::UploadedFile:0x000055d8d88e3620 @tempfile=#<Tempfile:/tmp/RackMultipart20200922-22723-11rsztq.jpg>, @original_filename="Amagi200.jpg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"upload\"; filename=\"Amagi200.jpg\"\r\nContent-Type: image/jpeg\r\n">, "ckCsrfToken"=>"dGHmsNCMmyP6O70viLj8129kRGSr4E7Q5NM1Glxy", "responseType"=>"json"}
Completed 500 Internal Server Error in 525ms (ActiveRecord: 3.4ms | Allocations: 5314)
  
Shrine::InvalidFile (#<ImageProcessing::Builder:0x000055d8d9697b90 @options={:source=>#<Tempfile: (closed)>, :loader=>{}, :saver=>{}, :format=>nil, :operations=>[[:resize_to_limit, [800, 800]]], :processor=>ImageProcessing::MiniMagick::Processor}> is not a valid IO object (it doesn't respond to #read, #eof?, #rewind, #close)):
  
config/initializers/ckeditor_shrine.rb:41:in `promote'

The Picture class is defined thusly:

module Ckeditor
  class PictureUploader < Shrine
    plugin :determine_mime_type
    plugin :validation_helpers
    plugin :derivatives, versions_compatibility: true

    Attacher.validate do
      validate_mime_type_inclusion %w[image/jpeg image/gif image/png]
      validate_max_size 2.megabytes
    end
    
    Attacher.derivatives_processor do |original|
      magick = SHRINE_PICTURE_PROCESSOR.source(original)
      {
        content: magick.resize_to_limit(800, 800),
        thumb:   magick.resize_to_limit(118, 100),
      }
    end
  end

  class Picture < Ckeditor::Asset
    include PictureUploader.attachment(:data)

    validates :data, presence: true

    def url_content
      data_url(:content)
    end

    def url_thumb
      data_url(:thumb)
    end

    def path
      data[:thumb].storage.path(data[:thumb].id)
    end

    def datasource
      @datasource ||= HashWithIndifferentAccess
                      .new(data)
                      .fetch(:thumb, OpenStruct.new(metadata: {}))
                      .metadata
    end
  end
end

And configured thusly:

# frozen_string_literal: true

require 'shrine'
# require 'shrine/storage/file_system'
require 'shrine/storage/s3'
require 'ckeditor/backend/shrine'

# Choose your favorite image processor
require 'image_processing/mini_magick'
SHRINE_PICTURE_PROCESSOR = ImageProcessing::MiniMagick

s3_props = { public: true,
  bucket: 'bucket-name',
  region: 'us-east-2',
  access_key_id: 'REDACTED',
  secret_access_key: 'REDACTED' 
}

Shrine.storages = {
  cache: Shrine::Storage::S3.new( prefix: 'subfolder/cache', **s3_props),
  store: Shrine::Storage::S3.new( prefix: 'subfolder/store', **s3_props),
}

Shrine.plugin :determine_mime_type
Shrine.plugin :activerecord
Shrine.plugin :instrumentation

Shrine.plugin :validation_helpers
Shrine.plugin :derivatives, versions_compatibility: true

class Shrine::Attacher
  def promote(*)
    create_derivatives
    super
  end
end

The last change I made was to update from the versions plugin to the new derivatives plugin, and everything was tested and working after that change.

Can you see any obvious mistakes here? I’m baffled how it could be losing the file between the initial upload (where you can see it has the file) and the initial resize, where it seems to be trying to resize a closed Tempfile.

The entire CKEditor/Shrine combo comes from here: https://github.com/walterdavis/ckeditor/tree/add_shrine_templates

Here’s the TL;DR of what I’ve added to the original Gem: https://github.com/galetahub/ckeditor/compare/master...walterdavis:add_shrine_templates

Thanks in advance,

Walter

Hi Walter, you forgot to add the ! to #resize_to_limit calls to tell ImageProcessing you want to execute the pipeline. Without !, ImageProcessing returns an ImageProcessing::Builder for chaining additional processing methods, and no processing is executed yet at that point. This must have changed since you last tested it, because ImageProcessing worked like this since version 1.0.

Thanks, Janko! The mystery gets deeper. Once I cleared that hurdle, my server complained that I didn’t have ImageMagick installed. And yet this used to work. WTF!

All better, now.

Walter