Writing strings as Carrierwave uploads

Updated . Posted . Visible to the public. Repeats.

When you have string contents (e.g. a generated binary stream, or data from a remote source) that you want to store as a file using Carrierwave, here is a simple solution.

While you could write your string to a file and pass that file to Carrierwave, why even bother? You already have your string (or stream).
However, a plain StringIO object will not work for Carrierwave's ActiveRecord integration:

>> Attachment.create!(file: StringIO.new(contents))
TypeError: no implicit conversion of nil into String

This is because Carrierwave expects a filename by default. It makes sense, so here is a simple yet useful helper class:

class FileIO < StringIO
  def initialize(stream, filename)
    super(stream)
    @original_filename = filename
  end

  attr_reader :original_filename
end

You must simply come up with a filename and can then pass your string or stream directly.

>> Attachment.create!(file: FileIO.new(contents, 'document.pdf'))
=> #<Attachment ...>

When using zeitwerk (Rails 6) you might also need to add an inflection in order to make autoloading work for this file:

ActiveSupport::Inflector.inflections(:en) do |inflect|
  inflect.acronym 'IO'
end

Otherwise zeitwerk will complain that the file file_io.rb does not define FileIo.

Profile picture of Arne Hartherz
Arne Hartherz
Last edit
Henning Koch
License
Source code in this card is licensed under the MIT License.
Posted by Arne Hartherz to makandra dev (2018-03-01 10:37)