How do you access the raw content of a file uploaded with Paperclip / Ruby on Rails?
Asked Answered
D

7

33

I'm using Paperclip / S3 for file uploading. I upload text-like files (not .txt, but they are essentially a .txt). In a show controller, I want to be able to get the contents of the uploaded file, but don't see contents as one of its attributes. What can I do here?

attachment_file_name: "test.md", attachment_content_type: "application/octet-stream", attachment_file_size: 58, attachment_updated_at: "2011-06-22 01:01:40"

PS - Seems like all the Paperclip tutorials are about images, not text files.

Deeplaid answered 2/7, 2011 at 6:30 Comment(1)
This answer should be the accepted answer.Brahmi
L
3

Here's how I access the raw contents of my attachment:

class Document

  has_attached_file :revision

  def revision_contents
    revision.copy_to_local_file.read
  end

end

Please note, I've omitted my paperclip configuration options and any sort of error handling.

Lofty answered 2/7, 2011 at 14:40 Comment(4)
New in 3.0.1: * API CHANGE: #to_file has been removed. Use the #copy_to_local_file method instead.Fides
This copy_to_local_file mentioned above doesn't work like that, as it expects 2 arguments for the style and the local destination path. rdoc.info/gems/paperclip/Paperclip/Storage/…Masqat
@Neel seems much better given the API changeNidus
You can do e.g: copy_to_local_file(nil, 'path_name') The style is for thumbnails and can be left nil to download the literal file, though this is a bit undocumented..Adust
N
104

In Paperclip 3.0.1 you could just use the io_adapter which doesn't require writing an extra file to (and removing from) the local file system.

Paperclip.io_adapters.for(attachment.file).read
Neel answered 22/4, 2014 at 0:45 Comment(5)
I see that actually this approach writes to local file system with the next log message: [paperclip] copying uploads/model/documents/1/Image1.jpg to local file /tmp/2fa67f482133f1c934235b73c2a0395420161123-27627-1xc7ieo.jpgGratitude
@Gratitude it looks like you are right for most adapters. If you want to avoid writing to disk you can use a StringIOAdapter: github.com/thoughtbot/paperclip/blob/master/lib/paperclip/…Neel
@jwadsack, what do I need to do to use a StringIOAdapter over the default FileAdapter?Epilogue
@Epilogue I was wrong. The adapters determine how the data is loaded. Even StringIOAdapter copies to a temporary file. My original response meant that you aren't adding your own local file write on top of what Paperclip does.Neel
thanks for the response, thats what I was finding in my investigation as well. I chose to go this route because a single file write which I can then read immediately into memory is better than managing my own file pointers.Epilogue
N
6

@jon-m answer needs to be updated to reflect the latest changes to paperclip, in order for this to work needs to change to something like:

class Document

  has_attached_file :revision

  def revision_contents(path = 'tmp/tmp.any')
    revision.copy_to_local_file :original, path
    File.open(path).read
  end
end

A bit convoluted as @jwadsack mentioned using Paperclip.io_adapters.for method accomplishes the same and seems like a better, cleaner way to do this IMHO.

Nail answered 28/11, 2016 at 20:18 Comment(0)
M
5

To access the file you can use the path method: csv_file.path http://rdoc.info/gems/paperclip/Paperclip/Attachment#path-instance_method

This can be used along with for example the CSV reader.

Masqat answered 13/12, 2013 at 16:22 Comment(2)
The return from csv_file.path is no longer a valid reference on the file system, at least for local storage. It now returns the path after the root... it returns /class_name/attachment_name/blah/blah rather than /rails_root/public/system/class_name/attachment_name/blah/blahTurki
Hmm, csv_file.path worked great for me for local file-system storage in Paperclip 4.3.2.Danie
L
3

Here's how I access the raw contents of my attachment:

class Document

  has_attached_file :revision

  def revision_contents
    revision.copy_to_local_file.read
  end

end

Please note, I've omitted my paperclip configuration options and any sort of error handling.

Lofty answered 2/7, 2011 at 14:40 Comment(4)
New in 3.0.1: * API CHANGE: #to_file has been removed. Use the #copy_to_local_file method instead.Fides
This copy_to_local_file mentioned above doesn't work like that, as it expects 2 arguments for the style and the local destination path. rdoc.info/gems/paperclip/Paperclip/Storage/…Masqat
@Neel seems much better given the API changeNidus
You can do e.g: copy_to_local_file(nil, 'path_name') The style is for thumbnails and can be left nil to download the literal file, though this is a bit undocumented..Adust
C
1

You would need to load the contents of the file (using Rubys File.open) into a variable before you show it. This may be an expensive operation if your app gets lots of use, so it may be worthwhile reading the contents of the file and putting it into a text column in your database after uploading it.

Celin answered 2/7, 2011 at 7:58 Comment(0)
S
1

Attachment already inherits from IOStream. http://rdoc.info/github/thoughtbot/paperclip/master/Paperclip/Attachment

So it should just be "#{attachment}" or <% RDiscount.new(attachment).to_html %> or send_data(attachment). However you wanted to display the data.

Spectator answered 2/7, 2011 at 14:57 Comment(0)
T
1

This is a method I used for upload from paperclip to active storage and should provide some guidance on temporarily working with a file in memory. Note: This should only be used for relatively small files.

Written for gem paperclip 6.1.0

Where I have a simple model

class Post
  has_attached_file :image
end

Working with a temp file in ruby so we do not have to worry about closing the file

  Tempfile.create do |tmp_file|
    post.image.copy_to_local_file(nil, tmp_file.path)

    post.image_temp.attach(
      io: tmp_file,
      filename: post.image_file_name,
      content_type: post.image_content_type
    )
  end
Tannatannage answered 7/4, 2021 at 15:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.