Как обрабатывать file_as_string (сгенерированный Prawn), чтобы он принимался Carrierwave?
Я использую Prawn для создания PDF файла из контроллера приложения Rails,
...
respond_to do |format|
format.pdf do
pdf = GenerateReportPdf.new(@object, view_context)
send_data pdf.render, filename: "Report", type: "application/pdf", disposition: "inline"
end
end
Это отлично работает, но теперь я хочу переместить GenerateReportPdf в фоновое задание и передать результирующий объект Carrierwave для прямой загрузки на S3.
Рабочий выглядит так:
def perform
pdf = GenerateReportPdf.new(@object)
fileString = ???????
document = Document.new(
object_id: @object.id,
file: fileString )
# file is field used by Carrierwave
end
Как обработать объект, возвращенный Prawn (?????
), чтобы убедиться, что это формат, который может быть прочитан Carrierwave.
fileString = pdf.render_file 'filename'
записывает объект в корневую директорию приложения. Поскольку я на Хереку, это невозможно.
file = pdf.render
возвращает ArgumentError: string contains null byte
fileString = StringIO.new( pdf.render_file 'filename' )
возвращает TypeError: no implicit conversion of nil into String
fileString = StringIO.new( pdf.render )
возвращает ActiveRecord::RecordInvalid: Validation failed: File You are not allowed to upload nil files, allowed types: jpg, jpeg, gif, png, pdf, doc, docx, xls, xlsx
fileString = File.open( pdf.render )
возвращает ArgumentError: string contains null byte
.... и т.д.
Что мне не хватает? StringIO.new( pdf.render )
кажется, что он должен работать, но я не понимаю, почему он порождает эту ошибку.
Ответы
Ответ 1
Оказывается, StringIO.new( pdf.render )
действительно должен работать.
Проблема, с которой я столкнулась, заключалась в том, что имя файла было задано некорректно и, несмотря на то, что ниже приведено описание на вики Carrierwave, ошибка в другом месте этого кода означала, что имя файла возвращалось как пустая строка. Я бы забыл об этом, предположил, что нужно что-то еще.
https://github.com/carrierwaveuploader/carrierwave/wiki/How-to:-Upload-from-a-string-in-Rails-3
мой код выглядел так:
def perform
s = StringIO.new(pdf.render)
def s.original_filename; "my file name"; end
document = Document.new(
object_id: @object.id
)
document.file = s
document.save!
end
Ответ 2
Вы хотите создать временный файл (который отлично подходит для Heroku, если вы не ожидаете, что он будет сохраняться через запросы).
def perform
# Create instance of your Carrierwave Uploader
uploader = MyUploader.new
# Generate your PDF
pdf = GenerateReportPdf.new(@object)
# Create a tempfile
tmpfile = Tempfile.new("my_filename")
# set to binary mode to avoid UTF-8 conversion errors
tmpfile.binmode
# Use render to write the file contents
tmpfile.write pdf.render
# Upload the tempfile with your Carrierwave uploader
uploader.store! tmpfile
# Close the tempfile and delete it
tmpfile.close
tmpfile.unlink
end
Ответ 3
Здесь вы можете использовать StringIO, как упомянул Энди Харви, но не добавляя метод к электограмме StringIO intstance.
class VirtualFile < StringIO
attr_accessor :original_filename
def initialize(string, original_filename)
@original_filename = original_filename
super(string)
end
end
def perform
pdf_string = GenerateReportPdf.new(@object)
file = VirtualFile.new(pdf_string, 'filename.pdf')
document = Document.new(object_id: @object.id, file: file)
end