Passing a custom file ID to storage

Hi there and first of all thank you for the good work you’re doing with shrine! :grinning:

I have some trouble wrapping my head around something so I thought, I’ll ask here.
Here’s what I want to do:

  • I have two different storage backends (filesystem, git)
  • When a user uploads file A to the filesystem backend and updates this item later, I want to keep both files (A1 and A2) for version auditing.
  • When a user uploads file A to the git backend and updates it later, I want to overwrite it as git takes care of the file versioning for me.

I’ve seen Customize file name and created a custom Uploader with a generate_location method that can do this for me.

But this uploader only puts the files in the :cache storage. At a later point in the flow, I’d like to use

attacher = Attacher.from_data(id: 'my_filename', storage: :cache)
attacher.promote(storage: :git_storage)

The last step (attacher.promote) somehow keeps creating a new filename. I don’t know where to hook into shrine in order to keep it from doing that or (ideally) provide the new name myself.

Any ideas?

Hi, you can keep the upload location in Shrine#generate_location, by retrieving the location of the cached file:

class MyUploader < Shrine
  def generate_location(io, **)
    if io.is_a?(UploadedFile) && io.storage_key == :cache
      io.id # use cached file's location
    else
      super # or whatever other location logic you have
    end
  end
end

Thank you for the reply!

I think I’ve missed some points in my explanation of what I’m trying to do.
I’m using shrine in a graphql environment.
There is a POST request where the user uploads a file. This gets handled by MyUploader and the files are stored in cache.
Afterwards, the user sends a mutation with the file_id telling the server which item the file should be attached to. The mutation would then move the file to its final destination (file storage, git storage). Currently I’m trying to solve this with

attacher = Attacher.from_data(id: 'my_filename', storage: :cache)
attacher.promote(storage: :git_storage)

Here I would like to keep the filename. Should I rather use an uploader here instead of an attacher?

Oh, I see, you want to retain the upload location only for this call. Yes, you can do this by passing the :location parameter:

attacher = Attacher.from_data(id: 'my_filename', storage: :cache)
attacher.promote(storage: :git_storage, location: 'my_filename')

Oh, that’s easier than I thought :grinning:
Will try it out, thanks a lot!