LoginSignup
3

More than 3 years have passed since last update.

wicked_pdfを導入するまで2020

Last updated at Posted at 2020-03-25

環境

  • OS
    • 開発PC: macOS Mojave
    • サーバー: Amazon Linux
  • ruby 2.6.1
  • Rails 5.2.2

初期段階

ミニマムで実装すると以下のようになります。
また、layoutで指定するファイルはapp/views/layoutsに配置する必要があります。

ディレクトリ構成
src
├── app
│   ├── assets
│   │   └── stylesheets
│   │       └── sample
│   │           └── sample.sass
│   ├── controller
│   │   └── sample
│   │       └── sample_controller.rb
│   └── views
│       ├── sample
│       │   ├── sample.html.slim
│       └── layouts
│           └── pdf_for_sample.html.slim
└── Gemfile 
sample_controller.rb
def generate_pdf
  respond_to do |format|
    format.html { redirect_to sample_generate_pdf_path(format: :pdf)}
    format.pdf do
      if params[:debug].present?
        render pdf: 'sample',
               title: 'sample.pdf',
               encoding: 'UTF-8',
               layout: 'pdf_for_sample.html.slim',
               template: "sample/sample.html.slim",
               show_as_html: params[:debug].present?
      else
        render pdf: 'sample',
               title: 'sample.pdf',
               encoding: 'UTF-8',
               layout: 'pdf_for_sample.html.slim',
               template: "sample/sample.html.slim",
               show_as_html: params[:debug].present?
      end
    end
  end
end
pdf_for_sample.html.slim
 doctype html 
 html[lang="ja" xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" dir="ltr"]
   head 
     / メインのcss 
     = wicked_pdf_stylesheet_link_tag 'sample/sample', media: 'all'
   body 
     .sample
       .sample-text コンテンツ
sample.html.slim
# 空っぽ
Gemfile
gem 'wicked_pdf'
gem 'wkhtmltopdf-binary'

layoutとtemplateを使い分ける

最初は違いがわかりにくかったのですが、layoutのファイルは共通、templateは個別のHTMLを描写するものとし、layoutからtemplateを呼び出す作りにするのが良さそうです。

pdf_for_sample.html.slim
 doctype html 
 html[lang="ja" xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" dir="ltr"]
   head 
     / メインのcss 
     = wicked_pdf_stylesheet_link_tag 'sample/sample', media: 'all'
   body 
     = yield
sample.html.slim
.sample
  .sample-text コンテンツ

A4横向き&pdfファイル全体に背景画像を使いたい

筆者の場合A4かつ横向きで生成する必要があったので、page_sizeorientationを指定します。
(page_sizeはデフォルトでA4なので指定は不要ですが、可読性のため明示的に指定しました)

sample_controller.rb
def generate_pdf
  respond_to do |format|
    format.html { redirect_to sample_generate_pdf_path(format: :pdf)}
    format.pdf do
      if params[:debug].present?
        render pdf: 'sample',
               title: 'sample.pdf',
               encoding: 'UTF-8',
               orientation: 'Landscape',  #横向き
               page_size: 'A4',
               margin: { top: 0,
                         bottom: 0,
                         left: 0,
                         right: 0 },
               layout: 'pdf_for_sample.html.slim',
               template: "sample/sample.html.slim",
               show_as_html: params[:debug].present?
      else
        render pdf: 'sample',
               title: 'sample.pdf',
               encoding: 'UTF-8',
               orientation: 'Landscape',  #横向き
               page_size: 'A4',
               margin: { top: 0,
                         bottom: 0,
                         left: 0,
                         right: 0 },
               layout: 'pdf_for_sample.html.slim',
               template: "sample/sample.html.slim",
               show_as_html: params[:debug].present?
      end
    end
  end
end

次にpdf全体を覆う背景画像を当て込みます。
デフォルトでmarginが設定されているので初期化し、かつA4に合うよう調整した結果、heightを991pxに設定しました。

sample.sass
.sample
  background: sample.png
  background-size: cover
  height: 991px

画面遷移を行わず、PDFのファイルダウンロードまで行いたい

筆者のPJでは生成したpdfファイルはユーザーのPCにダウンロードされる想定でしたが、このままだと、「ボタンクリックなどでPDF生成実行→pdfファイル画面へ遷移→ダウンロードボタンをクリック→ファイルがダウンロードされる」と言うフローになり、やや煩雑です。
上記を「ボタンクリックなどでPDF生成実行→ファイルがダウンロードされる」と言うフローにするため、以下の記述に変更します。

sample_controller.rb
def generate_pdf
  respond_to do |format|
    format.html { redirect_to sample_generate_pdf_path(format: :pdf) }
    format.pdf do
      if params[:debug].present?
        render pdf: 'sample',
               title: 'sample.pdf',
               encoding: 'UTF-8',
               orientation: 'Landscape',
               page_size: 'A4',
               margin: { top: 0,
                         bottom: 0,
                         left: 0,
                         right: 0 },
               layout: 'pdf_for_sample.html.slim',
               template: "sample/sample.html.slim",
               show_as_html: params[:debug].present?
      else
        pdf = render_to_string pdf: 'sample',
                               title: 'sample.pdf',
                               encoding: 'UTF-8',
                               orientation: 'Landscape',
                               page_size: 'A4',
                               margin: { top: 0,
                                         bottom: 0,
                                         left: 0,
                                         right: 0 },
                               layout: 'pdf_for_sample.html.slim',
                               template: "sample/sample.html.slim",
                               show_as_html: params[:debug].present?
        send_data pdf, filename: "sample.pdf"
      end
    end
  end
end

filename: "sample.pdf"でダウンロードされる際のファイル名が指定可能です。

Amazon LinuxでRuntime errorになる

環境依存問題その1
ローカルで動作確認をしていざデプロイ!と思ったらPDF生成実行で500エラー(Runtime error)となり動かない...
どうやら、AmazonLinuxは動作環境外のようでした。
調べてみるとAmazonLinux対応版のブランチがあるようなので、指定したら正常に動作しました。

Gemfile
gem 'wicked_pdf'
gem 'wkhtmltopdf-binary',
  git: 'https://github.com/entretechno/wkhtmltopdf_binary_gem',
  branch: 'amazon-linux'

日本語が文字化けする

環境依存問題その2
PDF生成の際にはクライアントではなくサーバー側のフォントを参照するらしく、日本語が文字化けしてまともに動かない状態に。
そのためサーバーに日本語フォントをインストールした上で、cssからスタイルに適用します。
今回はyumで手軽にインストール可能なIPAフォントを利用しました。
(本当はnotoなどのgoogleフォントが使えれば尚良かったのですが、筆者の環境では正常に読み込めませんでした)

sudo yum -y install ipa-gothic-fonts ipa-mincho-fonts
sample.sass
.sample
  background: sample.png
  background-size: cover
  height: 991px
.sample-text
  font-family: 'IPAMincho', 'IPA明朝'

また、serifsan-serifは、フォントをインストールしない状態でも描画可能だったので、試してみるといいかもしれません。

最終形

上記をまとめると以下になります。

sample_controller.rb
def generate_pdf
  respond_to do |format|
    format.html { redirect_to sample_generate_pdf_path(format: :pdf) }
    format.pdf do
      if params[:debug].present?
        render pdf: 'sample',
               title: 'sample.pdf',
               encoding: 'UTF-8',
               orientation: 'Landscape',
               page_size: 'A4',
               margin: { top: 0,
                         bottom: 0,
                         left: 0,
                         right: 0 },
               layout: 'pdf_for_sample.html.slim',
               template: "sample/sample.html.slim",
               show_as_html: params[:debug].present?
      else
        pdf = render_to_string pdf: 'sample',
                               title: 'sample.pdf',
                               encoding: 'UTF-8',
                               orientation: 'Landscape',
                               page_size: 'A4',
                               margin: { top: 0,
                                         bottom: 0,
                                         left: 0,
                                         right: 0 },
                               layout: 'pdf_for_sample.html.slim',
                               template: "sample/sample.html.slim",
                               show_as_html: params[:debug].present?
        send_data pdf, filename: "sample.pdf"
      end
    end
  end
end
pdf_for_sample.html.slim
 doctype html 
 html[lang="ja" xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" dir="ltr"]
   head 
     / メインのcss 
     = wicked_pdf_stylesheet_link_tag 'sample/sample', media: 'all'
   body 
     = yield
sample.html.slim
.sample
  .sample-text コンテンツ
sample.sass
.sample
  background: sample.png
  background-size: cover
  height: 991px
.sample-text
  font-family: 'IPAMincho', 'IPA明朝'
Gemfile
gem 'wicked_pdf'
gem 'wkhtmltopdf-binary',
  git: 'https://github.com/entretechno/wkhtmltopdf_binary_gem',
  branch: 'amazon-linux'

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
3