问题 如何处理file_as_string(由Prawn生成)以便Carrierwave接受它?


我正在使用Prawn从Rails应用程序的控制器生成PDF,

...
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' 将对象写入应用程序的根目录。因为我在Heroku上这是不可能的。

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 ) 好像它应该工作,但我不清楚为什么它产生这个错误。


9116
2017-07-18 04:11


起源



答案:


事实证明 StringIO.new( pdf.render ) 应该确实有效。

我遇到的问题是文件名设置不正确,尽管遵循Carrierwave的wiki下面的建议,代码中其他地方的错误意味着文件名作为空字符串返回。我忽略了这个假设需要别的东西

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

9
2017-07-20 13:29



您是如何解释代码中其他地方的“错误”的呢?我正面临着类似的问题。 - dax
@dax我在上面的答案中添加了代码。尝试一下,让我知道你是如何继续下去的 - Andy Harvey
谢谢你,在此期间我找到了 这个 来自imgkit的例子也适用于我 - dax
有没有其他方法可以做到这一点?我需要将变量名称传递给original_name函数,所以这对我来说并不适用。谢谢。 - tomascharad


答案:


事实证明 StringIO.new( pdf.render ) 应该确实有效。

我遇到的问题是文件名设置不正确,尽管遵循Carrierwave的wiki下面的建议,代码中其他地方的错误意味着文件名作为空字符串返回。我忽略了这个假设需要别的东西

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

9
2017-07-20 13:29



您是如何解释代码中其他地方的“错误”的呢?我正面临着类似的问题。 - dax
@dax我在上面的答案中添加了代码。尝试一下,让我知道你是如何继续下去的 - Andy Harvey
谢谢你,在此期间我找到了 这个 来自imgkit的例子也适用于我 - dax
有没有其他方法可以做到这一点?我需要将变量名称传递给original_name函数,所以这对我来说并不适用。谢谢。 - tomascharad


你想要创建一个临时文件(只要你不希望它在请求中持续存在,就可以在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

6
2017-07-20 10:38



这非常好用!唯一的问题是在文件名的末尾添加了一个奇怪的哈希,例如:[realFilename] .pdf20160803-42256-1ja9w8d - tomascharad


这里有一种方法可以像Andy Harvey一样使用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

0
2017-11-26 09:09