How to update meta data after direct upload to S3 from Javascript

82 views
Skip to first unread message

Pascal Lindelauf

unread,
Jun 29, 2015, 11:06:46 AM6/29/15
to dragonf...@googlegroups.com
Hi,

I'm using jquery-file-upload to upload images directly to S3. After the successful upload, I create an image object on my server, which has a Dragonfly "attachment" attribute. I assign the S3 upload path (which includes the filename) to the attachment_uid and the filename to attachment_name and save it. Then I schedule an asynchronous job to create a thumbnail of the image. 

This works fine, only that the attachment has no meta-data yet, which causes a problem when trying to determine the mime-type of the attachment (which is now reported as "application/octet-stream"). In this setup, it makes most sense to add the meta data in the same asynchronous job in which I'm creating the thumbnails. 

However, what is the correct way to do this? I found that I can do image.attachment.add_meta("name" => "the_filename.jpg"), but then how do I save this data? I tried image.attachment.job.store, but that creates a whole new object on S3 (at least a whole new UID). 

What is the correct way to do this? Please help!

Thanks,

Pascal

Pascal Lindelauf

unread,
Jul 1, 2015, 3:36:00 AM7/1/15
to dragonf...@googlegroups.com
So, after searching and experimenting a lot, I reached the conclusion that it might probably be best to not explicitly set the meta data myself, but have Dragonfly do that. To do this, I decided to "re-upload" the file through Dragonfly, using the URL of the image uploaded with Javascript as source. Once the image is "re-uploaded", we can then remove the originally uploaded image. All this is done in a "post_process" method on my image class, which is executed asynchronously:

    def post_process
      attachment_uid_after_upload = attachment_uid
      attachment_name_after_upload = self.attachment_name
  
      # Initialise a real Dragonfly attachment by assigning from URL.
      # This way all meta data is set and saved correctly. 
      self.attachment_url = File.join(s3_url, attachment_uid_after_upload)
  
      # We've seen spaces in filenames get replacesd by a literal '%20' string, 
      # which causes problems when trying to access this file on S3. 
      self.attachment.name = self.attachment_name.gsub("%20", " ")
  
      # Create the thumbnail
      self.thumb = attachment.thumb('100x100>')
      if self.save!
        # Clean up the initially uploaded image
        Dragonfly.app.datastore.destroy(attachment_uid_after_upload)
      end
    end

Even though it works, it does not feel like *the* best solution, since we're doing one upload too many. So I am still hoping to hear from anyone with a better approach to this. 

Anyone?

Thanks, Pascal

Op maandag 29 juni 2015 17:06:46 UTC+2 schreef Pascal Lindelauf:

Pascal Lindelauf

unread,
Jul 1, 2015, 4:50:50 PM7/1/15
to dragonf...@googlegroups.com
Oops... massive bug in the bit of source code: for some reason the filename and attachment name get URI encoded completely and that results in unusable URL's. In my code, I already substituted %20's, but that wasn't nearly enough. We had someone using Hebrew filenames and those got messed up completely. Here's the fix:

    def post_process
      attachment_uid_after_upload = attachment_uid
      attachment_name_after_upload = attachment_name
    
      # Initialise a real Dragonfly attachment by assigning from URL.
      # This way all meta data is set and saved correctly. 
      self.attachment_url = File.join(Catalog.s3_url, attachment_uid_after_upload)

      # We've seen spaces in filenames get replaced by a literal '%20' string,
      # but worse: we've seen Hebrew filenames leading to URI encoded names AND
      # URL's. The trick in getting both acceptable names AND URL's is to URI.decode
      # the attachment_name.
      self.attachment.name = URI.decode(attachment_name)
    
      # Create the thumbnail
      self.thumb = attachment.thumb('100x100>')
      if self.save!
        # Clean up the initially uploaded image
        Dragonfly.app.datastore.destroy(attachment_uid_after_upload)
      end
    end

Still hoping to hear about a leaner approach, though...

Thanks, Pascal

Op maandag 29 juni 2015 17:06:46 UTC+2 schreef Pascal Lindelauf:
Hi,

Frederick Cheung

unread,
Jul 2, 2015, 1:56:39 AM7/2/15
to dragonf...@googlegroups.com
It looks like the metadata is just stored as s3 headers - could you just make an API call to s3 to update those headers?

Fred

Sent from my iPhone
--
You received this message because you are subscribed to the Google Groups "Dragonfly" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dragonfly-use...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Pascal Lindelauf

unread,
Jul 2, 2015, 3:15:53 AM7/2/15
to dragonf...@googlegroups.com
Yes, that's correct. I probably could go via the fog-aws api... but I was hoping to that I might be able to do this on Dragonfly api level. That way my code could remain datastore agnostic, which will keep the code more testable.

Pascal.

Op donderdag 2 juli 2015 07:56:39 UTC+2 schreef Frederick Cheung:
Reply all
Reply to author
Forward
0 new messages