Generate pdf from Rails 3 - what tool to choose?

2019-02-06 10:28发布

问题:

I need to be able to render some views as PDFs from a Rails 3 project. I've never before used PDF generation techniques with ruby/rails, so I researched a few popular approaches such as Prawn and PDF::Writer, but all the examples and articles I found so far seem outdated and only applicable for rails 2.x. I haven't yet seen a working Rails3 example; tried myself installing prawn and the prawnto gems and reproducing the example described in this Railscasts episode, but I'm getting error of prawnto method not being recognized. I'm uncertain of whether this was an implementation error or just a sign of incompatibility, but seeing other people share on the web that prawn is no longer working for them in Rails3 I didn't bother tracing the code further.

Has anyone found a working reliable solution for pdf generation in Rails3? Could you possibly share it or point me to external resources and documentation? Big thanks!

回答1:

New answer to an old question, in case others stumble across this: WickedPDF (which uses wkhtmltopdf just like PDFkit) makes this a snap.

https://github.com/mileszs/wicked_pdf



回答2:

Prawn does work with Rails 3. I have personally used it with no problems. You do have to get the latest versions of the gem and the prawnto plugin for rails.

PDFkit does have the advantage of using the Webkit rendering engine, so you get to use CSS to define your layouts, and you get matching web pages for free with Safari and Chrome. It has a slightly nicer learning curve than Prawn.



回答3:

Have you seen PDFkit? I'm pretty sure that works with Rails 3, it is a piece of Rack middleware that can convert any HTML page to PDF that matches a route ending in .pdf



回答4:

About prawn, here is a seamless integration for Rails 3 that seems to work just fine: https://github.com/Whoops/prawn-rails



回答5:

You can use the Report gem, which generates PDF but also XLSX and CSV.

# a fake Manufacturer class - you probably have an ActiveRecord model
Manufacturer = Struct.new(:name, :gsa)

require 'report'
class ManufacturerReport < Report
  table 'Manufacturers' do # you can have multiple tables, which translate into multiple sheets in XLSX
    head do
      row 'Manufacturer report'
    end
    body do
      rows :manufacturers
      column 'Name', :name
      column 'GSA?', :gsa
    end
  end
  # you would want this so that you can pass in an array
  # attr_reader :manufacturers
  # def initialize(manufacturers)
  #   @manufacturers = manufacturers
  # end
  def manufacturers
    [
      Manufacturer.new('Ford', true),
      Manufacturer.new('Fischer', false),
      Manufacturer.new('Tesla', nil),
    ]
  end
end

When you call report.pdf.path, a PDF is generating in the tmp directory:

report = ManufacturerReport.new
puts report.pdf.path #=> /tmp/185051406_Report__Pdf.pdf
puts report.xlsx.path #=> /tmp/185050541_Report__Xlsx.xlsx

You can do it in your controller like:

@manufacturers = Manufacturer.all
respond_to do |format|
  format.html # index.html.erb
  format.json { render json: @manufacturers }
  format.pdf do
    report = ManufacturerReport.new(@manufacturers) # using the commented-out code
    send_file report.pdf.path, :type => 'application/pdf', :disposition => 'attachment', :filename => 'ManufacturersReport.pdf'
    # tmp files are periodically cleaned up by the operating system, but if you want to be extra clean you can call
    # report.cleanup
    # but this may remove the tmp files before apache/nginx/etc. finishes delivering the file
  end
end

End result:

PDF

XLSX

Note that the XLSX has an autofilter added for you automatically.