Support for CarrierWave::SanitizedFile and CarrierWave::Storage::Fog::File

63 views
Skip to first unread message

Martin Liptak

unread,
Jan 8, 2017, 12:16:42 PM1/8/17
to Prawn
I'm generating PDFs with a background image uploaded with Carrierwave. Carrierwave pseudo IO object is either CarrierWave::SanitizedFile (in development) or CarrierWave::Storage::Fog::File (in production). Both of them have read method, but they don't support rewind (and they can be read multiple times, it's always from the beginning). I checked Prawn code and discovered that it could be easily made more universal (possibly support other objects acting IO-like without rewind).

def verify_and_open_image(io_or_path)
 
# File or IO
 
if io_or_path.respond_to?(:rewind)
    io
= io_or_path
   
# Rewind if the object we're passed is an IO, so that multiple embeds of
   
# the same IO object will work
    io
.rewind
   
# read the file as binary so the size is calculated correctly
   
# guard binmode because some objects acting io-like don't implement it
    io
.binmode if io.respond_to?(:binmode)
   
return io
 
end
 
# String or Pathname
  io_or_path
= Pathname.new(io_or_path)
  fail
ArgumentError, "#{io_or_path} not found" unless io_or_path.file?
  io
= io_or_path.open('rb')
  io
end

The only method required after verify_and_open_image is read, but verify_and_open_image checks for rewind.

io = verify_and_open_image(file)
image_content
= io.read

How about checking for the read method in verify_and_open_image and making io.rewind optional, as io.binmode?

def verify_and_open_image(io_or_path)
 
if io_or_path.respond_to?(:read)
    io
= io_or_path
   
   
# Rewind if the object we're passed is an IO, so that multiple embeds of
   
# the same IO object will work
   
# Guard rewind because some objects acting io-like don't implement it
    io
.rewind if io.respond_to?(:rewind)


   
# Read the file as binary so the size is calculated correctly
   
# Guard binmode because some objects acting io-like don't implement it
    io
.binmode if io.respond_to?(:binmode)
   
    io
 
else
    path
= Pathname.new(io_or_path)
    fail
ArgumentError, "#{path} not found" unless path.file?
    io
= path.open('rb')
   
    io
 
end
end

I was able to work around the issue in my code like this

require "open-uri"

def prawn_image
 
if Rails.env.production?
    open
(model.uploader_url)
 
else
    model
.uploader.current_path
 
end
end

With the rewind guard it could look like this

def prawn_image
  model
.uploader.file
end

What do you think?

Alexander Mankuta

unread,
Jan 8, 2017, 5:04:49 PM1/8/17
to Prawn
Hello Martin,

We generally leave Prawn integration with third-party gems to the user. That is you, in this case.

You can easily simulate IO by passing StringIO.new(uploaded_file.read) to Prawn instead of CarrierWave objects..

--
Regards,
Alex

Martin Liptak

unread,
Jan 9, 2017, 3:36:51 PM1/9/17
to Prawn
Thanks, StringIO solved my issue.
Reply all
Reply to author
Forward
0 new messages