Delayed job to check if a carrierwave_direct upload has been completed and attached to a model

204 Views Asked by At

I'm using carrierwave_direct and delayed_job with user uploaded images. The process is:

  1. User drag & drops or selects a file.
  2. File is uploaded to S3 directly using carrierwave_direct to do all the form signing etc.
  3. User is presented with a dialog to crop their image, the key (from carrierwave_direct) is passed in through a hidden field. At this point no record exists in the database, but a file is stored on S3. Should the user now move away from the page, we will have an abandoned / unattached file on S3 that does not belong to any model.
  4. If user completes the process, a record will be created and processing (cropping and creating several thumbnail versions) is done by a worker queue.

I had to make a delayed job that is put into the queue as soon as the file is uploaded. It will have a delay of several hours (or days). This job checks to see if the file exists, then checks through all recently created image records in the database to see if any are attached to that file. If not, it deletes the file.

Lastly, I wanted to make use of Carrierwave classes to handle all the Fog stuff, since I was using it anyway.

I could not find this anywhere, so here is my version. Leaving this here for people to come across in the future.

1

There are 1 best solutions below

0
On BEST ANSWER

This is how I did it.

def new
    # STEP 1: Show upload dialog that user can drop an image unto
    @image = current_user.portfolio.images.new.images

    # Status 201 returns an XML
    @image.success_action_status = "201"
end

def crop
    # STEP 2: A file is now on Amazon S3, but no record exists in the database yet. Make the user crop the image and enter a title.
    # Meanwhile, also setup a delayed job that will later check if this step has been completed.
    # Note: the crop view gets retrieved and inserted using ajax in images.js.coffee
    @image = Image.new(key: params[:key])
    Delayed::Job.enqueue ImageDeleteIfUnattachedJob.new(params[:key]), 0, 15.minute.from_now.getutc

    render :partial => "images/crop.html.erb", :object => @image
end

ImageDeleteIfUnattachedJob = Struct.new(:key) do
  def perform
    # Do any of the images created in the last week match the key that was passed in?
    # If not, the user probably went through the upload process, which then either went wrong or was cancelled.
    unless Image.where("created_at > ?", 1.week.ago).order('created_at DESC').any? { |image| key == image.images.path }

        # We spawn these to let Carrierwave handle the Fog stuff.
        @uploader = ImageUploader.new
        @storage = CarrierWave::Storage::Fog.new(@uploader)
        @file = CarrierWave::Storage::Fog::File.new(@uploader, @storage, key)
        if @file.exists?
            # Indeed, the file is still there. Destroy it.
            @file.delete
        else
            return true
        end
    end
  end

  def max_attempts
    3
  end
end