はじめに
サーバーサイドは使い慣れているRailsで決定してから簡単にPDF化できるライブラリーはないのかということで色々検討した結果wicked_pdfを使うことになりました。
wicked_pdfとは?
wicked_pdfはHTMLを簡単にPDF化できる素晴らしいライブラリーです。内部でwkhtmltopdf-binaryを使ってMacやWindows、Linuxなど様々なプラットフォームに対応しています。
筆者の開発環境
- ローカル(MacOS High Sierra)
- ステージング(CentOS Linux release 7.6.1810 (Core))
- rails ~> 5.2.0
- wicked_pdf ~> 1.2.2
- wkhtmltopdf-binary ~> 0.12.4
wicked_pdfインストール
gem 'wicked_pdf'
gem 'wkhtmltopdf-binary'
wicked_pdfを使いやすくするためのラッパーモジュール
module Pdf
def save(file_name, template, force_save=false)
file_path = pdf_file_path(file_name)
return file_path if exist_pdf?(file_path) && !force_save
render pdf: file_name,
layout: 'pdf.html.erb',
template: template,
encoding: 'UTF-8',
page_size: 'A4',
margin: {
top: 10,
bottom: 10,
left: 20,
right: 20
},
dpi: '300',
save_to_file: file_path,
save_only: true
file_path
end
def show_html(file_name)
render pdf: file_name,
layout: 'pdf.html.erb',
encoding: 'UTF-8',
page_size: 'A4',
margin: {
top: 10,
bottom: 10,
left: 20,
right: 20
},
dpi: '300',
show_as_html: true
end
def exist_pdf?(file_name)
File.exist?(pdf_file_path(file_name))
end
def exist_pdf_directory?
File.directory?(pdfs_path)
end
def pdfs_path
Rails.application.config.pdfs_path
end
def pdf_file_path(file_name)
pdfs_path.join(file_name)
end
end
ここは要件に応じて調整します。僕の場合、いくつかの書類をペーパーレス化することが目的だったので共通モジュールを作りました。基本的にはsaveでPDFをローカルに保存、show_htmlはデバッグ用です。
コントローラー
class HogeController < ActionController::Base
include Pdf
before_action :find_target_employee, only: :new
before_action :set_doc_nda, only: [:destroy, :show]
def show
respond_to do |format|
format.html # html表示用
format.pdf do
file_name = "hoge.pdf"
# html表示
return show_html(file_name) if params[:debug].present?
# ファイルとして保存
file_path = save(file_name, 'show.pdf.erb')
send_file(file_path)
end
end
end
respond_toを利用して求められるフォーマットに応じてレスポンスしています。
htmlは画面に表示するだけ、pdfはローカルにPDF化し保存してからダウンロードします。
PDFビューテンプレート作成
<!doctype html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<%= wicked_pdf_javascript_include_tag 'application' %>
<%= wicked_pdf_stylesheet_link_tag 'application' %>
</head>
<body>
<%= yield %>
</div>
</body>
</html>
ベースとなるテンプレートです。全てのPDFはこのテンプレートを利用します。細かい調整は別ビューで調整します。
ビュー作成
hoge
上のPDFビューテンプレート作成
の<%= yield %>
の詳細をこのビューで書きます。
ここではシンプルにhoge
を表示するだけのPDFになりますが、ここにhtmlタグを書くだけでHTMLからPDF化できます。
ハマったところ
基本的には上記のようにしていけば問題ないかと思いますが、日本語の文字化けや開発環境と本番環境の文字サイズの違いなどハマりポイントが多かった。。。
日本語の文字化け1
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
UTF-8であることをうっかり忘れて(共通HTMLで書いたつもりで)日本語の文字化けになってなんでやねんとハマりました。
日本語の文字化け2
あれ?開発環境(Mac OSX)は問題ないのデプロイしてステージングで確認するとなぜか日本語が化けている?
色々調べたところ、該当する日本語のフォントがなかったからでした。
wicked_pdf で カスタムフォントを使う<--ここに書いてある通りにしてもずっと日本語が化けてたから謎々
yum install -y ipa-gothic-fonts && yum install -y ipa-mincho-fonts
ステージングでは上記のようにフォントをインストールすることで解決しました。なんか惜しい。。。
開発環境とステージング環境のフォントサイズの違いについて
これも結構ハマりましたね。。。引数にdpi: '300'
を設定することで対応しました。
僕の場合は印刷することもあるのでこのくらいが適切でした。
番外
リリースにCapistranoを使っているので、デプロイする前にPDFを保存するディレクトリがあるかどうかをチェックしてなかったらディレクトリを作るようにしています。
desc 'Make pdfs directory'
task :make_pdfs_dir do
on roles(:app) do
puts 'Make pdf directory'
execute :mkdir, '-p', shared_path.join('pdfs')
end
end
before 'deploy:check:directories', 'deploy:make_pdfs_dir'
desc 'Symlink pdfs directory'
task :symlink_pdfs_dir do
on roles(:app) do
puts 'Symlink pdfs directory'
tmp_current_pdfs_path = current_path.join("pdfs")
execute :ln, "-s", shared_path.join("pdfs"), tmp_current_pdfs_path
end
end
before 'deploy:finishing', 'deploy:symlink_pdfs_dir'
ローカル環境にあやまってコミットしないように.gitignore
に追加することも忘れず!
# pdf
pdfs/*