Edited at
PORTDay 13

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

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

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

prawnprawn-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

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



比べてみて

wickedはレンダリングされたhtmlをそのままpdfにできるので通常ならこっちの方が柔軟にpdfを作成できそう

prawnはコードは長くなるが、表や画像, テキストなどを任意の座標に置けるので、履歴書などフォーマットの決まったものなら、こっちでも十分作れそう


おまけ

履歴書サンプル完成しました。

スクリーンショット 2018-12-06 11.52.32.png

スクリーンショット 2018-12-06 11.52.40.png


募集

最後になりますが、PORT株式会社では自社サービスを支えてくれる優秀なエンジニアを募集しています。

ぜひprawnで履歴書を作成して応募いただけると幸いです。

話を聞いてみたい、会社を見てみたいといった方は弊社で開催している勉強会にお越しいただけるとイメージが湧きやすいと思いますので、そちらもぜひよろしくお願いします。

もくもく会ページ

https://freestyle-mokumoku.connpass.com/

酒がないとページ

https://sakeganaito.connpass.com/