Rubyでpdfを生成する

## やりたいこと

履歴書作成機能を作成したい。
でもExcelとかでテンプレ作って埋め込むの辛い。

## 理想

フォーム入力すると完成された履歴書のpdfが吐き出されるようにしたい。

---

## RubyでPDF生成する方法
- wicked_pdf
    - レンダリングしたviewをそのままpdfにできる
    - cssでスタイルを調整できる
- prawn
    - rubyのコードをゴリゴリ書いてpdf作る
    - なんか座標指定したりしてprocessingで遊んでる気分だった

---

## wicked_pdf
htmlからpdfの変換は実は`wkhtmltopdf-binay`というgemが担当している
`wicked_pdf`はそれをラップしてrubyから使えるようにしているらしい

gem install

```ruby
gem 'wkhtmltopdf-binary'
gem 'wicked_pdf'
```

wickedがwkhtmltopdfを使えるようにする

```wicked_pdf.rb
WickedPdf.config = {
  exe_path: "#{Gem.loaded_specs['wkhtmltopdf-binary-aml'].full_gem_path}/bin/wkhtmltopdf"
}
```

適当にルーティング

```routes.rb
get 'sample_pdfs/wicked', to: 'sample_pdfs#wicked'
```

適当にコントローラ作成

```sample_pdfs_controller.rb
def wicked
  respond_to do |format|
    # とりあえずデバッグモードで動かす
    format.html { redirect_to action: :show, format: :pdf, debug: true }
    format.pdf do
      render layout: 'mypage/sample_pdfs',
             pdf: 'sample',
             template: 'sample_pdfs/show.html',
             disposition: 'inline',
             page_size: 'A4',
             show_as_html: params.key?('debug')
    end
  end
end
```

適当にview作成

```wicked.html.slim
h1.title style="text-align: center; font-size: 100px;" wicked
p.date style="text-align: center; font-size: 50px;" = "#{l(DateTime.current)}"

table style="text-align: left; margin: auto; font-size: 50px;"
  thead
    tr
      th 名前
      th 年齢
      th 性別
      th 住所
  tbody
    tr
      td 井上
      td 22
      td 男
      td xxxx xxxx xxxx

div style="height: 500px; width: 500px; border: solid 1px red;"
```

出力

![スクリーンショット 2018-11-28 11.13.52.png](https://qiita-image-store.s3.amazonaws.com/0/147770/5bca5ba3-4233-3323-18b4-9ba624bf287d.png)

styleを直書きしているが、もちろんcssファイルを別にすることは可能
また画像を貼り付けたりも可能

ただし、imageタグやlinkタグなどをwicked_pdf独自のタグに書き換えなければならない

```
# js
wicked_pdf_javascript_include_tag "filename"
# css
wicked_pdf_stylesheet_link_tag "filename"
# image
wicked_pdf_image_tag 'filename'
```

正直これがかなりめんどくさい。
app/assetsの中しか読めないので、cssとかjsを`assets:precompile`とかして出力したのをassetsで読んでいる場合はかなりめんどくさい

---

## prawn

`prawn`と`prawn-table`をインストールする
`prawn-table`は表組みの作成に必要

```
gem 'prawn'
gem 'prawn-table'
```

app以下にprawnディレクトリを作成してその中にpdf出力用のクラスを作る

```sample_pdf.rb
class SamplePdf < Prawn::Document
  def initialize
    super()
    # 座標を表示
    stroke_axis
  end
end
```

適当にルーティングきって適当にcontroller作って適当にviwe作成

```sample_pdfs_controller.rb
def prawn
  respond_to do |format|
    format.html
    format.pdf do
      # PDF文書を作成
      pdf = SamplePdf.new

      # 画面にPDFを表示する
      # disposition: "inline" によりPDFはダウンロードではなく画面に表示される
      send_data pdf.render,
        filename:    "sample.pdf",
        type:        "application/pdf",
        disposition: "inline"
    end
  end
end
```

座標が表示されたpdf出力される

履歴書っぽい雛形を作ってみる

```sample_pdf.rb
class SamplePdf < Prawn::Document
  def initialize
    super()
    # 座標を表示
    stroke_axis
    font 'app/assets/fonts/ipaexm.ttf'
    move_down 10
    create_title
    create_profile
    create_address
  end

  def create_title
    table([
      [
        make_cell(content: '履歴書', width: 200, align: :left, size: 25),
        make_cell(content: I18n.l(Date.current, format: :long), width: 200, align: :right, size: 10, valign: :bottom)
      ]
    ], width:400) do
      row(0).borders = []
    end
  end

  def create_profile
    subtable = make_table([
      [
        make_cell(content: '生年月日', width: 70),
        make_cell(content: 'xxxx年 x月 xx日', width: 200, align: :center),
        make_cell(content: '性別', width: 50, align: :center),
        make_cell(content: '男', width: 80, align: :center)
      ]
    ], width: 400)

    kana_box = [
      make_cell(content: 'かな', width: 50),
      make_cell(content: 'xx xxxx', width: 350, align: :center)
    ]

    name_box = [
      make_cell(content: '氏名', width: 50),
      make_cell(content: 'xx xxx', width: 350, height: 40, align: :center, valign: :center, size: 20)
    ]

    data = [
      kana_box,
      name_box,
      [{ content: subtable, colspan: 2 }]
    ]

    table(data, position: :left, width: 400) do
      row(0).column(0).borders = [:top, :left]
      row(0).column(1).borders = [:right, :top]
      row(1).column(0).borders = [:top, :left]
      row(1).column(1).borders = [:top, :right]
      row(2).column(0).borders = [:top, :left, :right]
      row(1).border_lines = [:dashed, :solid, :solid, :solid]
    end
  end

  def create_address
    address_kana_box = [
      make_cell(content: 'かな', width: 50),
      make_cell(content: 'とうきょうとなかのくやよいちょう', width: 450, align: :center)
    ]

    address_box = [
      make_cell(content: '現住所', width: 50),
      make_cell(content: 'xxxxxxxxxxxxxxxxxx', width: 450, align: :center, size: 15)
    ]

    table([
      address_kana_box,
      address_box
    ], width: 500) do
      row(0).column(0).borders = [:top, :left]
      row(0).column(1).borders = [:right, :top]
      row(1).column(0).borders = [:top, :left, :bottom]
      row(1).column(1).borders = [:top, :right, :bottom]
      row(1).border_lines = [:dashed, :solid, :solid, :solid]
    end
  end
end
```

結果

![image.png](https://qiita-image-store.s3.amazonaws.com/0/147770/3a5c6925-32e5-fc75-0886-9fe9a633ec49.png)



途中までだけど履歴書っぽい

---

## 比べてみて
wickedはレンダリングされたhtmlをそのままpdfにできるので通常ならこっちの方が柔軟にpdfを作成できそう
prawnはコードは長くなるが、表や画像,　テキストなどを任意の座標に置けるので、履歴書などフォーマットの決まったものなら、こっちでも十分作れそう

## おまけ
履歴書サンプル完成しました。
<img width="696" alt="スクリーンショット 2018-12-06 11.52.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/147770/16cf9458-bf7e-15e8-d23d-64ec703c4cba.png">

<img width="694" alt="スクリーンショット 2018-12-06 11.52.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/147770/3d36eddb-6361-574e-5cc9-1b46145ace92.png">



## 募集
最後になりますが、PORT株式会社では自社サービスを支えてくれる優秀なエンジニアを募集しています。
ぜひprawnで履歴書を作成して応募いただけると幸いです。
話を聞いてみたい、会社を見てみたいといった方は弊社で開催している勉強会にお越しいただけるとイメージが湧きやすいと思いますので、そちらもぜひよろしくお願いします。

もくもく会ページ
https://freestyle-mokumoku.connpass.com/

酒がないとページ
https://sakeganaito.connpass.com/