Rails

【Rails】PDF出力が実装できるGem「Prawn」の実装方法について簡単に解説

Rails

 

今回はRailsでPDF出力を実装することができるGem「Prawn」について解説したいと思います。Web上でデータをPDF化して出力したい、PDFを商品として扱いたい、取引先がPDFを要求してきたなど、PDF化の需要は案外高いのではないでしょうか。PDF出力実装で悩んでいる方の参考になればと思います。

PDF出力の実装で悩んでいた時に、先輩エンジニアにPrawnを教わったのでその備忘録としても残しておきます。

RailsにおけるPDF出力実装

RailsにおけるPDF出力が実装できるライブラリは主には以下の3つです。

  • wicked_pdf
  • PDFKit
  • Prawn

これらそれぞれの特徴を簡単にまとめると以下のようになります。

カスタマイズ性開発コスト特徴
wicked_pdf低い低いHTMLをPDFに変換
PDFKit低い低いHTMLをPDFに変換
Prawn高い高いRubyをPDFに変換

参考: Excelで作成していた請求書を、Railsで自動作成できるようにした話

 

上記の表からも分かる通り、PrawnはRubyをPDFに変換し出力を行うためRubyエンジニアにとって比較的扱いやすいライブラリになっています。

Prawnとは

PrawnとはPDF出力機能を簡単に実装することができるgemです。

Prawnはpure Rubyで実装することができ、カスタマイズも多様であるため、RailsでPDF出力を実装する際の第一候補であるということができます。

白紙のPDFの表示

Prawnを用いた実装手順

では実際にPrawnを用いたPDF出力を実装してみましょう。

アプリケーションの作成

まずはrails newを実行し、新規アプリケーションを立ち上げます。

% rails new prawn-app -d mysql

アプリケーション名: prawn-app

Rails: 6.0.3.5

Ruby: 2.6.5

データベース: MySQL

データベースの作成

次にデータベースを作成しましょう。

% rails db:create
Created database 'prawn_app_development'
Created database 'prawn_app_test'

Prawnの導入

続いてはPrawnの導入です。

Gemfileにprawnとprawn-tableを記述し、bundle installを実行しましょう。

gem 'prawn'
gem 'prawn-table'
% bundle install
prawn-tableはPDF上で表を作成する際に必要となるgemです。

コントローラの導入

次にpost_pdf_controller.rbを作成します。

rails gコマンドでコントローラを作成しようとすると、不要なファイルが生成されてしまうため、エディタ上で直接作成しましょう。

ディレクトリ構成

app
  - controllers
    - application_controller.rb
    - post_pdf_controller.rb
# post_pdf_controller.rb

class PostPdfController < ApplicationController
  def index
  end
end
今回はindexアクションにPDF出力を行う処理を実装していきます。

ルーティングの編集

では、先程作成したpost_pdf_controller.rbのindexアクションに向けたルーティングを作成しましょう。

# routes.rb

Rails.application.routes.draw do
  resources :post_pdf, only: :index
end

途中経過

ここで一旦サーバーを立ち上げ、状態を確認してみます。

「localhost:3000/post_pdf」にアクセスし、missing a templateエラーが吐かれれば正常な挙動と言えます。

missing a templateエラー

PDFの作成

ではここから本題のPDF出力処理の実装を行っていきましょう。

まずはPDFを作成するクラスをlib直下に作成します。

ディレクトリ構成

lib
  - pdf
    - practice_pdf
      - post_pdf.rb
    - practice_pdf.rb
lib直下以外(app直下など)でも実装は可能です。

 

作成したpractice_pdf.rbとpost_pdf.rbに以下の記述をそれぞれ貼り付けましょう。

# lib/pdf/practice_pdf.rb

module PracticePdf
end
# lib/pdf/practice_pdf/post_pdf.rb

module PracticePdf
  class PostPdf < Prawn::Document
    def initialize
      super(page_size: 'A4') # 新規PDF作成
      stroke_axis # 座標を表示
    end
  end
end

 

それぞれのコードを順番に見ていきます。

まずpost_pdf.rbはPDF出力を担うメインファイルになるため、このファイルにPrawn::Documentを継承させています。

次にPostPdfクラスのinitializeメソッドでsuperを実行することにより、Prawn::Documentのinitializeメソッドが実行されます。それにより、A4サイズ白紙のPDFが生成されるようになります。

Ruby
【Ruby】メソッドのオーバーライドで用いるsuper(スーパー)クラスとは?メソッドのオーバーライド(上書き)に用いられる、super(スーパー)クラスについて解説しています。Railsでは、Deviseを継承したコントローラーを作成する際に登場するメソッドです。やや難しい概念ですが、この機会にしっかりマスターしておきましょう。...

 

stroke_axisはPDFの座標を表示する際に必要なオプションです。

application.rbの設定

先ほどlib直下にPDF出力を担うファイル群を作成しましたが、そのままでは正常に読み込みが行われません。

config/application.rbに以下の記述を追記し、lib直下のファイル群の読み込みが行われるように設定しましょう。

# config/application.rb

require_relative 'boot'

require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module PrawnApp
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 6.0

    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration can go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded after loading
    # the framework and any gems in your application.

    # 以下の記述を追記
    config.eager_load_paths += %W(#{Rails.root}/lib/pdf)
  end
end

コントローラの編集

ここまでの作業でPDFを作成する処理の実装ができました。

ここでは実際に作成したPDFの出力を行う実装を行っていきます。

post_pdf_controller.rbを以下のように編集しましょう。

# post_pdf_controller.rb

class PostPdfController < ApplicationController
  def index
    respond_to do |format|
      format.pdf do
        post_pdf = PracticePdf::PostPdf.new().render
        send_data post_pdf,
          filename: 'post_pdf.pdf',
          type: 'application/pdf',
          disposition: 'inline' # 外すとダウンロード
      end
    end
  end
end

 

順番に見ていきます。

まずは「format.pdf do」の記述によりpdf形式での出力処理をdo~end間で行います。

続いてPracticePdf::PostPdf.new().renderでインスタンスの生成を行い、その出力準備を行っています。

send_data以下はPDF出力に必要なオプションになるため、そのまま使用しましょう。(ファイル名は適宜変更してください)

disposition: ‘inline’はPDFをブラウザ上に出力する際に必要なオプションになります。この記述を外すことにより、出力ではなくPDFのダウンロードが行われます。

動作確認

ではサーバーを再起動し「localhost:3000/post_pdf.pdf」にアクセスしてみましょう。

以下のように、座標のみが表示された白紙のPDFが表示されれば成功です。

白紙のPDFの表示

リンクからPDF画面へ遷移

現在のままでは、直接「localhost:3000/post_pdf.pdf」とURLを打ち込まなければPDFを表示させることができません。

ここではリンクからPDFを表示できるように実装してみましょう。

まずはroutes.rbを編集し「localhost:3000/post_pdf」をrootパスに設定します。

Rails.application.routes.draw do
  root 'post_pdf#index'
end

 

続いてviews以下にpost_pdfフォルダを作成し、その直下にindex.html.erbを配置します。index.html.erbには以下の記述を追記しましょう。

ディレクトリ構成

app
  - views
    - layouts
      - appliacation.html.erb
      - mailer.html.erb
      - mailer.text.erb
    - post_pdf
      - index.html.erb
# app/views/post_pdf/index.html.erb

<%= link_to "PDFを表示", root_path(format: "pdf") %>

 

サーバーを再起動し、以下のようにリンクからPDFが表示されれば成功です。

Image from Gyazo
クリックすることで上記GIFは拡大表示できます。

PDFのカスタマイズ

ここからはPDFのカスタマイズについて見ていきましょう。

文字の配置

PDF上に文字を配置するにはtext_boxオプションを使用することで実現できます。

lib/pdf/practice_pdf/post_pdf.rbを以下の記述に変更しましょう。

module PracticePdf
  class PostPdf < Prawn::Document
    def initialize
      # 新規PDF作成
      super(page_size: 'A4')
      # 座標を表示
      stroke_axis

      header
    end

    def header
      text_box 'ヘッダー'
    end
  end
end

 

しかしこのままPDFを開こうとすると下記画像のようなエラーが吐かれてしまいます。

Fontエラー

 

こちらのエラーはフォントを指定してあげることで解消することができます。

まずは以下のリンクからフォントをダウンロードしましょう。

↓ ↓ ↓

フォントのダウンロード
アップデート等により上記と異なる場合があります。最新版のフォントをダウンロードするように注意しましょう。

 

続いてapp/assets以下にfontsフォルダを作成します。

fontsフォルダには先程ダウンロードしたフォントを配置しましょう。

フォントの配置

 

全てのフォントを表示するため、post_pdf.rbの記述も以下のように変更します。

module PracticePdf
  class PostPdf < Prawn::Document
    def initialize
      # 新規PDF作成
      super(page_size: 'A4')
      # 座標を表示
      stroke_axis

      header
    end

    def header
      font FONT
      text_box 'ヘッダー'

      font FONT_BOLD
      text_box 'ヘッダー', at: [0, 730], size: 10

      font FONT_EXTRALIGHT
      text_box 'ヘッダー', at: [0, 700], size: 20

      font FONT_HEAVY
      text_box 'ヘッダー', at: [0, 650], size: 30

      font FONT_LIGHT
      text_box 'ヘッダー', at: [0, 600], size: 40

      font FONT_MEDIUM
      text_box 'ヘッダー', at: [0, 550], size: 50

      font FONT_NORMAL
      text_box 'ヘッダー', at: [0, 500], size: 60
    end
  end
end
at: [0, 730]等でフォントの位置を調整しています。

 

サーバーを再起動し、PDFを開いてみましょう。

以下のようにフォントとサイズが異なる文字が配置されたかと思います。

文字の配置

テーブルの配置

テーブルを配置するにはtableオプションを使用し、二次元配列でテーブル構成を記述する必要があります。

post_pdf.rbを以下のように変更してみましょう。

module PracticePdf
  class PostPdf < Prawn::Document
    def initialize
      # 新規PDF作成
      super(page_size: 'A4')
      # 座標を表示
      stroke_axis

      cols = [
        ['banana', 'apple', 'peach'],
        ['kiwi', 'grape', ''],
        ['cherry', 'watermelon', '']
      ]
      table cols
    end
  end
end

 

サーバーを再起動し、PDFを開くと以下のようなテーブルが表示されるかと思います。

テーブルの表示

画像の表示

最後にPDF上に画像を表示させてみましょう。

画像はimageオプションを使用することで実装が可能です。

まずは適当な画像をapp/assets/images以下に配置しましょう。

画像の配置
上記の場合、画像のファイル名はsample.jpegとしています。

 

post_pdf.rbを以下のように編集しましょう。

module PracticePdf
  class PostPdf < Prawn::Document
    def initialize
      # 新規PDF作成
      super(page_size: 'A4')
      # 座標を表示
      stroke_axis

      image 'app/assets/images/sample.jpeg', at: [10, 200]
    end
  end
end
at: [10, 200]で画像の位置を調整しています。

 

サーバーを再起動し、再度PDFを開いてみましょう。

以下のように、assets/images直下に配置した画像が表示されているはずです。

画像の表示

まとめ

  • 代表的なPDF出力を実装するライブラリはwicked_pdf、PDFKit、Prawnの3種類
  • PrawnとはPDF出力機能を簡単に実装することができるgem
  • Prawnはpure Rubyで実装することができ、カスタマイズも容易
  • 文字の配置にはtext_boxオプションを使用する
  • テーブルの配置にはtableオプションを使用する
  • 画像の配置にはimageオプションを使用する

参考

 

 

今回はRailsでPDF出力を実装することができるGem「Prawn」について解説しました。PDF出力を実装する機会は多くはないかもしれませんが、必要になった際の参考になればと思います。