Rails環境でPDFを出力しようとしたら、思ったより躓いたので、備忘録として残しておきたいと思います。
やりたいこと
端的に言うと、HTMLをPDFで出力できるようにするgemが「wicked_pdf」です。
「wicked_pdf」のほかにもいろいろな種類のPDFを出力できるgemがありますが、今回は簡単に作れるwicked_pdfを紹介します。
利用環境・前提
AWSアカウントを所持していて、cloud9の画面を開けることが前提条件です。
Rails 5.1.7を利用しています。
Rails側の処理
Railsアプリの作成
cloud9の開発環境を作るまでは省略します。こちらのページの「AWS Cloud9 環境を作成する」の章が終わっていることを前提とします。
Railsアプリを作成します。
rails new pdfapp
作成したRailsアプリのディレクトリに行きます。
cd ./pdfapp/
Herokuに送るためのgemの書き換え
初期設定のdbはsqliteですが、Herokuではpostgresqlしか使えないのでgemを編集します。

gemfileのこの部分を削除して、
gem 'sqlite3'
このように変更します。
#すでにあるgroup内に追記する
group :development, :test do
gem 'sqlite3', "~> 1.3.6"
end
#ここからGemfileの最後の行に追記する
group :production do
gem 'pg'
end
gem 'wicked_pdf'
gem 'wkhtmltopdf-binary'
#ここまで
Gemfileの保存後(ctrl+s)にターミナルで以下のコマンドを実行します。
bundle install --without production
wicked_pdfの設定
先ほどインストールしたwicked_pdfを使って、PDFを作っていきます。
イニシャライザを作成します。
rails g wicked_pdf
上のコマンドを打った時、以下のように帰ってくれば大丈夫です。

次に、pdfapp/config/initializers/wicked_pdf.rbを開きます。
すでに、
WickedPdf.config = {
}
このように書かれていますが、これに、以下のようにします。
WickedPdf.config = {
exe_path: "#{Gem.loaded_specs['wkhtmltopdf-binary'].full_gem_path}/bin/wkhtmltopdf"
}
保存(ctrl+S)を忘れずにしてください。
フォントのアップロード
何もしなくてもPDFは出力はできますが、日本語が文字化けするので、フォントを追加します。
こちらのサイト(IPA:独立行政法人情報処理推進機構)の、2書体パックをダウンロードしてください。
Cloud9に戻り、pdfapp/.fontsというフォルダーを新規作成し、そのフォルダー内に、ダウンロードしたフォントデータ(.ttf)を入れます。

画像のようにアップロードできていれば大丈夫です。
フォルダー名の「.fonts」の「.」ドットを忘れないようにしてください。
とりあえず動かしてみよう
ターミナルで、
rails g controller post index
を動かし、
pdfapp/config/routes.rbを、書き換えます。
Rails.application.routes.draw do
get "/post/index.pdf"=>"post#index"
end
次に、pdfapp/app/controllers/post_controller.rbを書き換えます。
class PostController < ApplicationController
def index
respond_to do |format|
format.html
format.pdf do
render pdf: 'post',
layout: 'pdf',
encording: 'UTF-8',
template: 'post/index',
orientation: 'Landscape'
end
end
end
end
pdfapp/app/views/post/index.html.erbのファイル名の末尾を、index.pdf.erbに変更したうえで、名前の変更後のファイルを、
<h1>HELLOPDF</h1>
<h1>PDFで出力</h1>
このように書き換えます。
pdfapp/app/views/layoutsに、pdf.pdf.erbファイルを新規作成し、以下のように入力します。
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
</head>
<body>
<div id="content">
<%= yield %>
</div>
</body>
</html>
お疲れさまでした。(変更したファイルはすべて保存できていますか?)
とりあえず、ローカル環境で動かしてみましょう。
ターミナルで、
rails s
Preview→PreviewRunningApplication

を押して、

このボタンを押して出てきたタブのURLの末尾に、「/post/index.pdf」を付けると、アクセスができ...

ませんが、これが正常です。
自分は、これが正常とも知らず、2~3日悩みました。
おそらくCloud9の仕様上仕方無いエラーなのだとは思います。本番環境ではしっかり動くので安心してください。
(Cloud9環境でPDFをしっかり出力できる方法があったら教えてください。)
Git&Herokuの処理
githubのアカウントを作る
githubとHerokuのアカウントを作成しましょう。
githubのサイトにアクセスし、New repositoryをクリックします。

次の画面で、Repositoryの名前を設定し、公開範囲を「Private」にします。
(既定の設定だと、Public:公開になっているので注意してください。)

次の画面で、SSHを選択したうえで、赤枠のgit@から始まるものメモ帳などにコピーしてください。

gitする
ターミナルに戻ります。
git init
git add -A
git commit -m "first"
cat ~/.ssh/id_rsa.pub
もし最後のコマンド実行時にNo such file or directoryが出てきたら、
ssh-keygen
と実行した後に再度
cat ~/.ssh/id_rsa.pub
を実行する。
最後のcatコマンド実行後に、ssh-rsaから始まる長い英数字の羅列が返ってきたと思います。これを全文コピーします。
githubに戻って、settings→SSHandGPGkeys→NewSSHKeyに、先ほどコピーしたものを入力して保存します。



保存後、ターミナルに戻って、
git push git@github.com:**********/********.git master
#git@...は先ほどメモ帳にコピーしたやつ(sshから始まる方じゃないよ!)
エラーが出なければ、git完了です。
あと少しで、公開できます。頑張ってください。
Herokuのアカウントを作る
herokuにアクセスし、アカウントを作ります。
ログイン後、ここ(ダッシュボード)にアクセスし、右上のNew→CreateNewapp

他人と重複しない( availableと表示される)アプリ名を入力し、CreateAppを押します。

[ad]
Herokuにデプロイする
次は、GitHubとHerokuを結びつけます。Deploy→GitHubを選択し、

先ほど、作成したGitHubでログインします。
この記事で使用した名前を使っていれば、Searchのところに、「pdfapp」と入れれば、先ほど保存したレポジトリが出てくると思うので、「connect」を選択します。

ページの下の方にある、[DeployBranch]を選択します。

少し待つと(1~2分)、このように成功と表示されるので、その下のViewをクリックします。

PDFの出力
Viewを押すと、エラーが出ますが、

URLの末尾に、「/post/index.pdf」を付けます。つまり、「https://**********.herokuapp.com/post/index.pdf」にアクセスしてください。
はい。出力できました。

エラー時の対処
日本語が四角になってる→日本語フォントの導入ミス
PDFが出力されない→何らかのファイルがそもそもないorミスってる
この記事の説明が分かりにくい→「参考」のURLの方が分かりやすいかも
まとめ
いかがでしたでしょうか。Railsで簡単にPDFを出力できたと思います。
請求書とか、いろいろなものを出力できるようにしたら、利便性の高いアプリが作れるかもしれません。
より容易に理解できるよう、できうる限り特殊なタイプのものを使わず、できうる限りGUIを使うようにし、ファイルパスはできる限りアプリファイルからの絶対パスで書くように努力しました。
上に書いてある通りにやったけど、できないから教えてほしいってときは、この記事のコメントか、TwitterのDMで聞いてくれれば教えられる範囲で教えます。
コメント