Correct approach for promoting from cache to store

I’m still quite inexperienced with Shrine. I think it’s great; it’s impressive and the documentation is vast, but, um, I guess it’s a bit too vast because it’s so flexible I’m not sure what the correct approach is. Anyway… I’m using a solution with Uppy and the Upload Endpoint approach.

Simplified as

class UploadsController < ApplicationController
  def image_assets
    set_rack_response(ImageAssetUploader.upload_response(:cache, request.env))
  end
end

The model with the attachment is:

class ImageAsset < ApplicationRecord
  include ImageAssetUploader::Attachment(:asset)
end

And the Uploader is:

class ImageAssetUploader < Shrine
  plugin :add_metadata
  plugin :upload_endpoint, url: true

  add_metadata do |io, context|
    {
      hash_sha256: Digest::SHA256.hexdigest(io.read)
    }
  end

  Attacher.promote_block do
    UploadImageAssetJob.perform_now(self.class.name, record.class.name, record.id, name)
  end
end

Which is basically calling a background worker to handle this uploaded file (including uploading to the cloud).

But the attached file always remains in the cache store.

In my worker, there’s a point where it determines whether everything processed fine. I’m wondering if that’s the best place to handle the cache --> store promotion. Eg…

class UploadImageAssetJob < ApplicationJob
  def perform(attacher_class, record_class, record_id, name)
    image_asset = Object.const_get(record_class).find(record_id)
    # ... do stuff ...

    if upload_success
      # <--- should I call image_asset.asset.finalize here?
    end
  end
end

Is this reasonable? Or is there some other plugin or callback where this type of thing is best handled?

Thanks in advance!

I guess I should have checked that finalize actually made a difference before I posted.

image_asset.asset_attacher.cached? # => true
image_asset.asset_attacher.stored? # => false
image_asset.asset_attacher.finalize

My understanding of the docs what that would promote the file to the store, yet

image_asset.asset_attacher.cached? # => true
image_asset.asset_attacher.stored? # => false

So I guess I’m somewhat missing the point with the whole cache/store concept and how to manage it.

Ok, so are you using Rails? I assume you are, as you are using ApplicationRecord, but I’d like to confirm. And if yes, can you post your initializers/shrine.rb file as well? I want to know if you are using the active_record and backgrounding plugins, which you should be

Because if you are using rails, and using the ActiveModel plugin, the default flow is:

  • You use the upload endpoint to, well, upload the image, and as a response you get some metadata with shrine-readable information about the image.
  • You can directly assign this information to a record (ImageAsset.new.image = data_you_got_from_upload_endpoint). For an unsaved object, the image stays in the cache
  • Once you call save on the object, Shrine will automatically promote it to the permanent store. It does all of that on its own, you shouldn’t really have to worry about uploading to the cloud, there are plugins for at least S3 and GCS, and a lot more, which cloud storage are you using?