Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Link existing S3 file as paperclip attachment

I have an external service that creates files and stores them into S3 (that my Rails app has access too).

I want to be able to use Paperclip in order to store that S3 object, as well as a thumbnail of it. I haven't been able to find documentation on how to use Paperclip with files that are already on S3. So, my code should look like:

page = Page.find(3)
page.s3_url = s3_url # I have the s3 route. And I would need to generate a thumbnail too.
page.save

So, in other words:

How can I tell PaperClip that my attachment is already in S3?

EDIT:

Here is what I have so far:

I know the file_name, the content_length and the content_type of the file that is already uploaded in S3. So, since the association is a Page has_attached_file :screenshot

This is what I do:

@page = Page.find(3)
@page.update_attributes(screenshot_content_type: screenshot_content_type, screenshot_file_size: screenshot_file_size, screenshot_update_at: screenshot_updated_at, screenshot_file_name: screenshot_file_name)

So, now I can do:

@page.screenshot and I see the paperclip object. However, when I do:

@page.screenshot.url => The url is not the one that I originally stored the image.

like image 591
Hommer Smith Avatar asked Jul 28 '14 18:07

Hommer Smith


1 Answers

I've managed to solve this problem with paperclip interpolations:

  1. Define in your model a field, witch would store path to the uploaded files
  2. Load the paperclip attachment info to DB through property update
  3. With interpolations specify a paperclip attachment :path, so it first looks for uploaded file, and then for default
  4. Profit!

This will do the trick, because of how S3 storage composes urls:

path: This is the key under the bucket in which the file will be stored. The URL will be constructed from the bucket and the path. This is what you will want to interpolate. Keys should be unique, like filenames, and despite the fact that S3 (strictly speaking) does not support directories, you can still use a / to separate parts of your file name.

Here are more details with code:

Model

class MyModel
    has_attached_file :file, path: ":existent_file_or_default", storage: :s3
end

Paperclip interpolations

Put this under config/initializers

Paperclip.interpolates :existent_file_or_default do |attachment, style|
  attachment.instance.existent_file_path ||
    attachment.interpolator.interpolate(":class/:attachment/:id_partition/:style/:filename", attachment, style)
end

Attach existent items

MyModel.create({
  existent_file_path: "http://your-aws-region.amazonaws.com/your-bucket/path/to/existent/file.jpeg",
  file_file_name: "some_pretty_file_name.jpeg",
  file_content_type: "image/jpeg",
  file_file_size: 123456
})
like image 64
Alex Shtuk Avatar answered Oct 17 '22 11:10

Alex Shtuk