15

I have a rake file, that reads content via HTTP and I want to use Paperclip to store the loaded content on Amazon S3. It works fine when I provide a local file, but I would like to set the content as a string and set the content type manually.

The following does not work. No error is issued, the database entry is updated, but no file is created in S3:

p.attachment = "Test"
p.attachment_file_name = "test.txt"
p.attachment_content_type = "text/plain"
p.attachment_file_size = "Test".size
p.attachment_updated_at = Time.now
p.save

I guess I could write a temporary file with my content, but that would be a pretty inefficient solution.

Jan
  • 3,044
  • 3
  • 20
  • 32

5 Answers5

44

To avoid littering the filesystem with temp files, you can use StringIO as in:

p.attachment = StringIO.new(your_string)
Leopd
  • 41,333
  • 31
  • 129
  • 167
  • 4
    Great little workaround. Once you do this, set your attachment file name with `p.attachment_file_name = 'test.txt'` and you're all set. – Joshua Pinter May 14 '15 at 15:46
8

It's a bit late but I pulled it off by creating a Tempfile using ruby 1.9.2 rails 3.1

file = Tempfile.new( ["file_name", '.txt'] )
file.write( "my test string".force_encoding('utf-8') )
p.attachment = file
Aaron Renoir
  • 4,283
  • 1
  • 39
  • 61
  • this will actually create a file... https://ruby-doc.org/stdlib-1.9.3/libdoc/tempfile/rdoc/Tempfile.html – olivervbk Oct 10 '17 at 20:35
  • Just make sure you call unlink when you're done with the temp file: https://ruby-doc.org/stdlib-1.9.3/libdoc/tempfile/rdoc/Tempfile.html#method-i-unlink – Michael Sep 28 '18 at 14:28
4

For both paperclip and carierwave I end up creating a class like this. It has both methods needed to mock a file upload which they like to see.

class FakeFileIO < StringIO
  attr_reader :original_filename
  attr_reader :path

  def initialize(filename, content)
    super(content)
    @original_filename = File.basename(filename)
    @path = File.path(filename)
  end
end

Works like a dream

reconbot
  • 5,138
  • 6
  • 45
  • 63
2

No, you have to create a file with your string.

Just look at the Paperclip source code : https://github.com/thoughtbot/paperclip/blob/master/lib/paperclip/attachment.rb#L77 and https://github.com/thoughtbot/paperclip/blob/master/lib/paperclip/iostream.rb#L5

when you assign something using my_model.attachment=, Paperclip wants a file object.

Nicolas Blanco
  • 11,164
  • 7
  • 38
  • 49
  • That's unfortunate. Do you think I should use something else than Paperclip then? I would like to keep the chance of switching from S3 to file system easily, but I don't have user file uploads, so Paperclip might be the wrong choice. – Jan Nov 04 '10 at 09:44
  • 1
    have you looked at carrierwave : https://github.com/jnicklas/carrierwave that seems a great alternative... – Nicolas Blanco Nov 04 '10 at 09:47
1

Similar to Aarons but with the proper block method as suggested by Ruby:

...one should always call unlink or close in an ensure block.

file = Tempfile.new('test.txt')

begin
  file.write( "Test" )

  p.attachment = file
  p.save              

  # Whatever else you might need to do with the TempFile.

ensure
  file.close
  file.unlink   # Deletes the temp file.
end
Joshua Pinter
  • 45,245
  • 23
  • 243
  • 245