Read more

Writing strings as Carrierwave uploads

Arne Hartherz
March 01, 2018Software engineer at makandra GmbH

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.

Illustration web development

Do you need DevOps-experts?

Your development team has a full backlog? No time for infrastructure architecture? Our DevOps team is ready to support you!

  • We build reliable cloud solutions with Infrastructure as code
  • We are experts in security, Linux and databases
  • We support your dev team to perform
Read more Show archive.org snapshot

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.

Posted by Arne Hartherz to makandra dev (2018-03-01 11:37)