見出し画像

Rails prawnを用いたPDF生成

こんにちは。HANOWAエンジニアの佐々木です。

今回は結構前ですが、HANOWAでprawnというgemを用いてRailsにてPDFを生成する機能を実装したので、そちらについてお話しさせていただきます。
以前公開した、AIを活用して開発効率を上げる(ChatGPT、GithubCopilot)で少し話にあげているのでこちらの記事ももしよろしければ見て頂ければと思います。

Prawnとは

PDF生成ができるgemです。なぜなのかは把握してませんが意味はエビ🦐らしいです。
他にもPDFを生成するgemはいくつかありますが、PrawnはコードでPDFを生成するタイプのためかなり細かい作り込みが可能になります。

HANOWAではもともとフロント側でPDF生成を行なっておりました。HTML、CSSで作成したものをPDF化するという感じです。フロントで行うと処理が重くなってしまいますし、テクニカルな処理は極力サーバーサイド側で行いたいという意向があり、Prawnを用いてRails側でPDF生成を行う決断をしました。

私はフロントエンド出身なので、少し慣れるまでに時間がかかりましたが記事も充実しているので、案外なんとかなりました。

導入

gem 'prawn'
gem 'prawn-table'

まずはgemを追加します。prawn-tableというのはテーブルを作成するのに使用するので、一緒に入れておくことをお勧めします。

controller

コントローラーに直接、PDFを作成するコマンドを書き込んでも良いのですが、長くなることが多いため可読性や保守性の観点から別途クラスを作成して管理することにしました。

class Api::GenerateResumePdfController

  # 履歴書PDFを生成する
  def resume_pdf_data
    pdf_content_params = {
      name: 'sample name',
      address: '大阪府大阪市...',
      phone_num: '090-1234-5678',
    }

    pdf = ResumePdf.new(pdf_content_params)
    send_pdf(pdf, "resume.pdf")
  end
end

こんな感じでコントローラーはかなりシンプルになりました。PDF生成に使用するパラメータは今回はサンプルなので直接記載していますが、別途サービスクラスを作るかシリアライザーなどで必要な情報だけ渡すようにするのが良いと思います。

PDF生成クラス

class ResumePdf < Prawn::Document
  def initialize(params)

    super(
      page_size: 'A4',
      top_margin: 40,
      bottom_margin: 30,
      left_margin: 20,
      right_margin: 20
    )

    # 日本語フォント
    font "app/assets/fonts/ipaexm.ttf"

    text "#{params[:name]}", size: 12
    text "#{params[:address]}", size: 16
    text "#{params[:phone_num]}", size: 20
  end
end

super内でページのサイズや上下左右のマージン等を設定できます。page_sizeについてはA4やB3のような指定方法とpage_size: [1024, 512]のようなサイズ指定も可能です。
デフォルトで日本語対応していないので、別途使用したいフォントをダウンロードしておく必要があります。(著作権は気をつけましょう)

実際に表示される内容は以下のようになります。

生成されたPDF

渡したパラメータが正しく表示されていますね。
次はテーブルを用いた実装を試してみましょう。履歴書PDFを生成するクラスを想定しているので少しそれっぽくしてみます。

// controller

class Api::V1::GeneratePdfController < Api::BaseController

  # 履歴書PDFを生成する
  def resume_pdf_data
    pdf_content_params = {
      name: 'HANOWA太郎',
      name_kana: 'ハノワタロウ',
      address: '大阪府大阪市...',
      phone_num: '090-1234-5678',
      birthdate: '1990年1月1日',
      email: 'sample@hanowa.co.jp',
      today: Time.zone.today.strftime("%Y年%m月%d日"),
    }

    pdf = ResumePdf.new(pdf_content_params)
    send_pdf(pdf, "resume.pdf")
  end
// PDF生成クラス

class ResumePdf < Prawn::Document
  def initialize(params)
    super(
      page_size: 'A4',
      top_margin: 40,
      bottom_margin: 30,
      left_margin: 20,
      right_margin: 20
    )
       stroke_axis

    # 日本語フォント
    font "app/assets/fonts/ipaexm.ttf"

    @params = params

    # contents
    header
    move_down 35
    table_basic_info
  end

  private

  def header
    text_box "履歴書", size: 18, at: [0, 770], valign: :bottom, height: 30
    indent(420) do
      text_box "#{@params[:today]}現在", size: 10, at: [0, 770], valign: :bottom, height: 30
    end
  end

  def table_basic_info
    base_table = [
      ["フリガナ", @params[:name_kana]],
      ["氏名", @params[:name]],
      ["生年月日", @params[:birthdate]],
      ["連絡先", @params[:address]],
      ["電話番号", @params[:phone_num]],
      ["E-mail", @params[:email]]
    ]
    table base_table,
      column_widths: [50, 460] do
        cells.size = 10
      end
  end
end
生成されたPDF

少しだけそれっぽくできたでしょうか。
パラメータも増やして、テーブルを生成する記載を追加しました。
可読性を上げるために各パーツごとにプライベートメソッドに切り出しています。
stroke_axisという記載を追加していますが、これは左側と下側についたメモリを表示する設定です。最終的には外しますが、実装中はmove_down 35のように座標をもとに位置指定をする必要があるため表示しておくとわかりやすいです。

まとめ

今回はPrawnを用いたRailsでのPDF生成方法を紹介いたしました。
もっとカスタマイズすることも可能なので、要件が細かいPDF生成が必要な際には活用できると思います。
英語で量もかなり多いですが、公式マニュアルもあるのでこちらも参考にしていただければと思います!

HANOWAでは他のメンバーもnoteを書いているので、ぜひ見に行ってみてください!

この記事が気に入ったらサポートをしてみませんか?