railsでpdfを描画する
はじめに
請求書や発注書をweb上で作成して
ユーザーが閲覧・保存できるようにする際に、何かいい方法がないかなと調べたら
何やらrailsにprawn
と呼ばれるgemがあるらしく試してみました。
Reactなどでもreact-pdf
を使えばpdfの描画はできますが
今回はrailsを使用して、URLを叩けばpdfが見れるようになるというのを一旦ゴールとします。
prawnを使う準備
今回pdfを表示・作成するのに使うgemはprawn
というgemです。
tableの描画もすることがあると思うのでprawn-table
も合わせてインストールしましょう。
gem 'prawn'
gem 'prawn-table'
公式のマニュアル (量が多いです。
https://prawnpdf.org/manual.pdf
ちなみに、少し大きめのエビのことをprawnというらしいです。
コントローラーの準備
コントローラを作成します。
pdf_controller.rb
class PdfController < ApplicationController
def index
end
end
ルーティングの準備
resources :pdf, only: :index
日本語フォントの準備
日本語フォントを使用しないと日本語の描画でエラーが出ます
好みのfontをダウンロードして下記に置いておきましょう
今回はIPAexフォントというのを使ってみます
app/assets/font
PDFの作成
PDFを作成するクラスをlib直下に作成します。
ディレクトリ構成
lib
- contract
- pdf.rb
lib/contract/pdf.rb
module Contract
class Pdf < Prawn::Document
def initialize
super(
page_size: 'A4',
top_margin: 20,
bottom_margin: 20,
left_margin: 20,
right_margin: 20
)
stroke_axis # 座標を表示
font "#{Rails.root}/app/assets/fonts/ipaexm.ttf"
# 日本語のテキストを描画
text_box '契約書(けいやくしょ)', at: [50, 750], size: 20
# テーブルの描画
bounding_box([50, 700], width: 500, height: 300) do
table_data = [
["項目", "説明", "価格"],
["商品A", "商品Aの説明", "¥1000"],
["商品B", "商品Bの説明", "¥2000"],
["合計", "", "¥3000"]
]
table(table_data, header: true) do
columns(1..2).align = :right
self.row_colors = ['DDDDDD', 'FFFFFF']
self.header = true
end
end
end
end
end
サンプルなのでこんな感じでおk
コントローラの編集
class PdfController < ApplicationController
def index
respond_to do |format|
format.pdf do
pdf = Contract::Pdf.new().rende
send_data pdf,
filename: 'pdf.pdf',
type: 'application/pdf',
disposition: 'inline' # 外すとダウンロードになる
end
end
end
end
動作確認
/pdf.pdf
を叩いてpdfが描画されれば動作確認完了。
おそらく下記のような物が出てくるはず、試しに描画しただけなのでしょぼいです。
レイアウトについて
prawnを用いいたpdf描画のレイアウトに関してですが
基本的に座標上に要素を置いていくことになります。
なので開発中はstroke_axis
を追加して、座標が常に表示されるようにしましょう。
また、1ページに内に収まらないという場合も
オプションで次ページに送るものがあるので それも用いれば何ページでも作れます。
試しに先ほどのpdfを下記のように修正してみましょう
module Contract
class Pdf < Prawn::Document
def initialize
super(page_size: 'A4', margin: [40, 40, 40, 40])
font_path = "#{Rails.root}/app/assets/fonts/ipaexm.ttf"
font font_path
stroke_axis
header
contract_info
parties
terms
move_cursor_to signature_position
signature
end
private
def header
text '契約書', size: 24, align: :center
move_down 10
end
def contract_info
text "契約日: YYYY年mm月dd日", size: 12, align: :right
move_down 10
end
def parties
text '当事者:', size: 16
indent(20) do
text "甲方: 株式会社A"
text "乙方: 株式会社B"
end
move_down 10
end
def terms
text '契約の条項:', size: 16
indent(20) do
text "1. 契約の目的"
text "2. 契約の条件"
text "3. 支払い条件"
text "4. 終了条件"
end
move_down 10
end
def signature_position
bounds.bottom + 30
end
def signature
signature_start = 300
indent(signature_start - bounds.left) do
text '署名:', size: 14
move_down 5
stroke_line [0, cursor], [200, cursor]
end
end
end
end
見た目しょぼいけどさっきよりはマシでしょう。
各メソッドの説明
先ほどのアップデートしたpdfのメソッドの説明です。
-
header
文書のヘッダー(タイトル)を生成
text メソッドは指定されたテキストを描画し、size と align オプションでフォントサイズと配置を設定します。 -
contract_info
契約の日付などの情報を表示
テキストとして描画します。 -
partiesメソッド:
契約の当事者に関する情報を表示
indent メソッドでテキストのインデント(字下げ)を設定します。 -
termsメソッド
契約の条項を表示します。
ここでも indent メソッドを使用します。 -
signature_positionメソッド:
署名欄の位置を計算します。
bounds.bottom はページの底部の位置を返し、それに30を加えて署名欄の位置を下にずらします。 -
signatureメソッド
署名欄を生成します。
indent メソッドで署名のテキストと署名欄の位置を調整し、stroke_line で署名線を描画します。
こんな感じでindent
やmove_down
での調整もできるし
textもsize
やalign: :right
などでいろいろ調整できそう。
最後に
今回railsでpdfを描画するgemのprawnを使用して見ました!
慣れるまで自分の思い描いたレイアウトにするのは難しそうですが
簡単にpdfの描画やDLができるのはとても良いと思いました。
バックエンドでの実装なので、DBのデータなども簡単に渡して描画できたりと、出来ることは沢山ありそうでした!
興味がある方は是非試してみてください!
Discussion