はじめに
Rails5でPDFの作成をするのに便利なgemのPrawnの使用方法について、備忘録的にまとめておきます。どなたかの役に立てば幸いです。
環境
Rails | 5.1.6 |
---|
データベースはmysqlを使用
gemの導入
まずはprawn導入用のgemをGemfileに追記します。
gem 'prawn'
gem 'prawn-table'
bundle installします。
$ bundle install
ローカルサーバー等は再起動してください。
PDF用のクラスを作成
PDFの内容を作成するための専用クラスを作成します。
Prawnではcontrollerに直接PDFの内容を流し込んでもいいのですが、可読性・保守性ともに下がるため、専用のクラスを作成することがおすすめです。
$ mkdir app/pdfs
$ touch app/pdfs/record_pdf.rb # record_pdf.rbというファイル名で作成、model名はRecordPdfとなる
PDF作成用のモデルを作成します。
Prawn::Documentを継承するようにします。
class RecordPdf < Prawn::Document
# recordにモデルなどのデータを渡します
def initialize(record)
# superで初期設定を指定します(ページサイズ、マージン等)
super(
page_size: 'A4',
top_margin: 40,
bottom_margin: 30,
left_margin: 20,
right_margin: 20
)
@record = record # インスタンスを受け取り。コンポーネント作成時などにレコード内のデータを使える
end
end
フォントを指定
Prownはデフォルトでは日本語に対応していないので、日本語用のフォントを用意します。
日本語のフォントはここからダウンロードできます。
ダウンロードしたフォントはassets/fontsに入れます。
(ちなみにここ以外から入手したフォントでも動作できます。著作権に注意してください。)
class RecordPdf < Prawn::Document
def initialize(record)
super(
page_size: 'A4',
top_margin: 40,
bottom_margin: 30,
left_margin: 20,
right_margin: 20
)
font 'app/assets/fonts/ipaexg.ttf' # fontをパスで指定
@record = record
end
end
controllerの作成
controllerを作成します。すでに作成済みのコントローラを介して使用することもできます。
$ rails g controller record_pdfs index # コントローラ作成時にindexページも作成
class RecordPdfsController < ApplicationController
def index
@records = Record.all # pdf上で使用するレコードのインスタンスを作成
respond_to do |format|
format.html
format.pdf do
# pdfを新規作成。インスタンスを渡す。
pdf = RecordPdf.new(@records)
send_data pdf.render,
filename: "sample.pdf",
type: "application/pdf",
disposition: "inline" # 画面に表示。外すとダウンロードされる。
end
end
end
end
PDFの表示
ページへのリンクはルーティングに依存するので、適宜確認して行ってください。
リンクの作成例は以下のようになります。
<%= link_to "PDFを表示", 適宜指定_path(format: "pdf") %>
モデルを編集します。
class RecordPdf < Prawn::Document
def initialize(record)
super(
page_size: 'A4',
top_margin: 40,
bottom_margin: 30,
left_margin: 20,
right_margin: 20
)
font 'app/assets/fonts/ipaexg.ttf'
@record = record
# きちんと日本語も表示されるか確認
text 'hello こんにちは 春夏秋冬'
end
end
カスタマイズ
Prawnは座標指定でテキスト等の表示位置を決められるため、グリッドを表示させておくと編集が楽。
class RecordPdf < Prawn::Document
def initialize(record)
super(
page_size: 'A4',
top_margin: 40,
bottom_margin: 30,
left_margin: 20,
right_margin: 20
)
@record = record
font 'app/assets/fonts/ipaexg.ttf'
stroke_axis # これでメモリが表示される
text 'hello こんにちは 春夏秋冬'
end
end
基準となるメモリが表示される
PDF内のコンポーネント作成
class RecordPdf < Prawn::Document
def initialize(record)
super(
page_size: 'A4',
top_margin: 40,
bottom_margin: 30,
left_margin: 20,
right_margin: 20
)
@record = record
font 'app/assets/fonts/ipaexg.ttf'
stroke_axis
# 下記で作成したコンポーネントを表示順に
header
move_down 50
contents
end
# コンポーネント作成
def header
text 'PDFのタイトル', size: 50
move_down 20
text '作成者氏名', size: 14
end
def contents
text '本文'
move_down 10
text 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
end
end
表示確認
インスタンスの利用
コントローラで渡して入れば、データベースから取得したデータをPDF内で利用可能
class RecordPdfsController < ApplicationController
def index
@records = Record.all # pdf上で使用するレコードのインスタンスを作成
respond_to do |format|
format.html
format.pdf do
pdf = RecordPdf.new(@records) # ここで受け取っている
send_data pdf.render,
filename: "sample.pdf",
type: "application/pdf",
disposition: "inline" # 画面に表示。外すとダウンロードされる。
end
end
end
end
class RecordPdf < Prawn::Document
def initialize(record) # 受け取ったものがrecordに入っている
super(
page_size: 'A4',
top_margin: 40,
bottom_margin: 30,
left_margin: 20,
right_margin: 20
)
@record = record # メソッドで利用できるようにインスタンス化
font 'app/assets/fonts/ipaexg.ttf'
stroke_axis
# 下記で作成したコンポーネントを表示順に
header
move_down 50
contents
end
# コンポーネント作成
def header
text 'PDFのタイトル', size: 50
move_down 20
text '作成者氏名', size: 14
end
def contents
text '本文'
move_down 10
text 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
move_down 50
text "データの内容は#{@record.data}です" # 例えば、このように利用できる
end
end
以上です。