LoginSignup
9
4

More than 5 years have passed since last update.

Rails5 + wicked_pdf導入のメモ

Posted at

はじめに

サーバーサイドは使い慣れている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を使いやすくするためのラッパーモジュール

lib/pdf.rb
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はデバッグ用です。

コントローラー

app/app/controllers/hoge_controller.rb
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ビューテンプレート作成

app/views/layouts/pdf.html.erb
<!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はこのテンプレートを利用します。細かい調整は別ビューで調整します。

ビュー作成

app/views/show.pdf.erb
hoge

上のPDFビューテンプレート作成<%= yield %>の詳細をこのビューで書きます。
ここではシンプルにhogeを表示するだけのPDFになりますが、ここにhtmlタグを書くだけでHTMLからPDF化できます。

ハマったところ

基本的には上記のようにしていけば問題ないかと思いますが、日本語の文字化けや開発環境と本番環境の文字サイズの違いなどハマりポイントが多かった。。。

日本語の文字化け1

app/views/layouts/pdf.html.erb
<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/*
9
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
4