You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails应用中基于多模型数据生成PDF的实现方案咨询

Great question! Let’s dive in—first off, Prawn absolutely supports generating single PDFs from multiple models in your Rails app. It’s actually one of the most flexible options for this use case, since you have full control over how you pull and format data from different sources. Let’s walk through how to use it, plus cover other popular gems that might fit your workflow better if you prefer working with HTML/CSS instead of direct Ruby code.

Prawn: Multi-Model PDF Example

Step 1: Set Up the Gem

Add Prawn to your Gemfile:

gem 'prawn'

Run bundle install to install it.

Step 2: Create a PDF Generator Class

Create a dedicated class (e.g., app/pdfs/combined_report_pdf.rb) to handle the PDF generation—this keeps your controllers clean and makes the code reusable:

class CombinedReportPdf
  def initialize(user)
    @user = user
    @orders = user.orders.includes(:products) # Pull related orders and products in one query
    @pdf = Prawn::Document.new
  end

  def generate
    add_user_info
    add_orders_list
    add_product_summary
    @pdf.render
  end

  private

  def add_user_info
    @pdf.text "User Report: #{@user.name}", size: 20, style: :bold
    @pdf.text "Email: #{@user.email}"
    @pdf.move_down 20
  end

  def add_orders_list
    @pdf.text "Recent Orders", size: 16, style: :bold
    @orders.each_with_index do |order, index|
      @pdf.text "#{index + 1}. Order ##{order.id} (Placed: #{order.created_at.strftime('%Y-%m-%d')})"
      @pdf.text "Total: $#{order.total_amount}"
      @pdf.move_down 10
    end
    @pdf.move_down 20
  end

  def add_product_summary
    @pdf.text "Purchased Products", size: 16, style: :bold
    all_products = @orders.flat_map(&:products).uniq
    all_products.each do |product|
      @pdf.text "- #{product.name}: $#{product.price} (Ordered #{product.orders.count} times)"
    end
  end
end

Step 3: Use the Class in Your Controller

In your controller (e.g., users_controller.rb), add an action to generate and send the PDF:

def generate_report
  @user = User.find(params[:id])
  pdf = CombinedReportPdf.new(@user).generate
  send_data pdf, filename: "user_report_#{@user.id}.pdf", type: "application/pdf", disposition: "inline"
end

That’s it! This pulls data from User, Order, and Product models and combines them into a single, structured PDF.

Alternative Gems for Multi-Model PDFs

If you’d rather build your PDF layout using HTML/CSS (which is great for complex designs or if you already have ERB templates), these gems are perfect:

Wicked PDF

Wicked PDF uses wkhtmltopdf under the hood to convert HTML/CSS views into PDFs. It’s super intuitive if you’re comfortable with Rails views.

Setup & Usage

  1. Add the gem to your Gemfile:
gem 'wicked_pdf'
gem 'wkhtmltopdf-binary' # Includes the binary so you don't need to install it separately

Run bundle install.

  1. Create an ERB template (e.g., app/views/users/generate_report.pdf.erb) that pulls data from multiple models:
<h1>User Report: <%= @user.name %></h1>
<p>Email: <%= @user.email %></p>

<h2>Recent Orders</h2>
<ul>
  <% @user.orders.each do |order| %>
    <li>Order #<%= order.id %> - Placed on <%= order.created_at.strftime('%Y-%m-%d') %> - Total: $<%= order.total_amount %></li>
  <% end %>
</ul>

<h2>Purchased Products</h2>
<ul>
  <% @user.orders.flat_map(&:products).uniq.each do |product| %>
    <li><%= product.name %> - $<%= product.price %> (Ordered <%= product.orders.count %> times)</li>
  <% end %>
</ul>
  1. Update your controller action:
def generate_report
  @user = User.find(params[:id])
  respond_to do |format|
    format.pdf do
      render pdf: "user_report_#{@user.id}",
             template: "users/generate_report.pdf.erb",
             disposition: "inline"
    end
  end
end

Grover

Grover uses Puppeteer (a headless Chrome instance) to render HTML/CSS into PDFs, which means it supports modern CSS features (flexbox, grid, etc.) that older tools might struggle with.

Setup & Usage

  1. Add the gem:
gem 'grover'

Run bundle install, then run rails generate grover:install to set up the initializer.

  1. Create the same ERB template as above (or any HTML/CSS view tailored to your needs).

  2. Controller action:

def generate_report
  @user = User.find(params[:id])
  html = render_to_string(template: "users/generate_report.pdf.erb", layout: "pdf") # Use a dedicated PDF layout if needed
  pdf = Grover.new(html).to_pdf
  send_data pdf, filename: "user_report_#{@user.id}.pdf", type: "application/pdf", disposition: "inline"
end

PDFKit

Similar to Wicked PDF, PDFKit uses wkhtmltopdf but has a simpler API for basic use cases. It’s lightweight and easy to set up.

Setup & Usage

  1. Add gems:
gem 'pdfkit'
gem 'wkhtmltopdf-binary'

Run bundle install.

  1. Create an initializer (config/initializers/pdfkit.rb):
PDFKit.configure do |config|
  config.wkhtmltopdf = Rails.root.join('bin', 'wkhtmltopdf').to_s if Rails.env.development?
end
  1. Controller action:
def generate_report
  @user = User.find(params[:id])
  html = render_to_string(template: "users/generate_report.pdf.erb")
  kit = PDFKit.new(html)
  pdf = kit.to_pdf
  send_data pdf, filename: "user_report_#{@user.id}.pdf", type: "application/pdf", disposition: "inline"
end

内容的提问来源于stack exchange,提问作者Jul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 19:28:12