4

我有大量产品要以 pdf 格式显示,并带有类别标题。如果某个类别不适合当前页面,我想将其移至下一个。为此,我使用了 Prawn 的 group 方法。

Product.all.group_by(&:category).each do |category, products|
  pdf.group do
    # Simplified the data a bit for this example
    pdf.text category
    pdf.table products.map{ |p| [p.title, p.price] }
  end
end

这对于少量产品非常有效,但是当我添加超过 100 个左右时,它需要很长时间,然后以“无法分配内存”结束。如果我不使用 group 方法,大约需要 30 秒。

显然 group 方法不能很好地管理它的内存使用。任何解决方法的建议将不胜感激。

4

2 回答 2

2

我在一个项目上使用了 prawn,很抱歉,但这是一场灾难,最后我们不得不切换到wicked pdf。我建议你在不需要太多代码之前也这样做。

于 2010-11-18T02:51:47.310 回答
1

---------- 更新的答案--------

以前的解决方法对于生产服务器来说不够好,所以我不得不使用来自 git repo 的开发版本作为 vendor/prawn 下的子模块安装,如下所述:https ://github.com/sandal/prawn/wiki/使用-Prawn-in-Rails

group 方法的内存问题已经消失,但事物的语法/选项发生了一些变化。所以我不得不重写代码来生成PDF。

此外,让子模块与 Rails 应用程序的 git 存储库很好地配合是很困难的。部署到生产环境非常困难。

---------- 原始答案--------

这不是一个修复方法,但它使问题在出现之前需要更多的组迭代:

  • 覆盖名为“组”的 Prawn::Document 实例方法
  • 使用来自 prawn 最新开发版本(来自 github.com)的 'group' 函数中的代码

我这样做的方式是在我的 Rails 应用程序的 /lib 文件夹中添加了一个文件。该文件将包含 Prawn gems 并为 PDF 文档定义 mime 类型:

class PdfPrawn
  require 'prawn'
  require 'prawn/core'
  require 'prawn/table'
  MIME_TYPE = "application/pdf"
end
class Prawn::Document
  def group(second_attempt=false)
    old_bounding_box = @bounding_box
    @bounding_box = SimpleDelegator.new(@bounding_box)

    def @bounding_box.move_past_bottom
      raise RollbackTransaction
    end

    success = transaction { yield }

    @bounding_box = old_bounding_box

    unless success
      raise Prawn::Errors::CannotGroup if second_attempt
      old_bounding_box.move_past_bottom
      group(second_attempt=true) { yield }
    end

    success
  end
end

然后在模型文件中,我定义了一种方法来生成我的 PDF 并使用如下内容:

def to_pdf
  require "#{File.expand_path(RAILS_ROOT)}/lib/pdf_prawn"
  pdf = Prawn::Document.new
  # code to add stuff to PDF
  pdf.render
end
于 2011-03-24T20:10:43.430 回答