Rails からの印刷出力
|
Rails からの印刷を考えます。Rails に限らず、web システムからの印刷は結構厄介そうです。
そこで、まずはPDFへの出力を検討します。
調べてみると、ruport なるものがありました。
インストールは簡単で、
gem install ruport
gem install ruport-util
|
で可能です。ruport は、pdf-writer を利用するらしい。
ActiveRecord から出力するには、
class User < ActiveRecord::Base
acts_as_reportable
end
class RuportController < ApplicationController
def userlist
send_data User.report_table.to_pdf,
:type => "application/pdf",
:filename=> 'userlist.pdf',
:disposition => 'inline'
end
end
|
こんな感じになります。すこぶる簡単です。が、PDFお決まりの落とし穴が。
漢字が出ません。2バイト文字が扱えないのです。これはそもそも pdf-writer が対応していないかららしく、UTF-8 対応も、pdf-writer の対応待ちらしいです。
さて、漢字なしならOKかというと、このままではチト問題が。項目の出力順序が意図したとおりに並ばないのです。select とか、only とか付けてもダメで、しばし悩む。
解決策は次の通りです。
reorder('Field1', 'Field2', 'Field3')
|
みたいな感じで、順序の指定が可能です。判ってしまえばこれも簡単です。
と、ここまで検証したところで、PDF には見切りを付けました。フリーソフトで日本語を扱うのが難しそうだからです。
次に、PXDoc による出力を検証します。
PXDoc は、xml ベースのテキストを成形印刷する仕組みです。テキストファイルなので出力の作成は柔軟に出来そうですが、クライアントに専用ソフトのインストールが必要になります。PDF でも出力に専用ソフトは必要ですが、PXDoc は PDF のリーダーほどメジャーでないのが欠点でしょうか。
Rails からPXD形式で出力するには、例えば sample_controller.rb に、
def report
@samples = Sample.find(:all)
@response.headers["Content-Type"] = 'application/pxd'
@response.headers["Content-Disposition"] = 'inline;filename="report.pxd"'
render(:layout => false)
end
|
の様にしておきます。対応する view は、
.rhtml ではなく、report.rxml とし、
xm = Builder::XmlMarkup.new
xml << '<?xml version="1.0" encoding="utf-8"?>'
xml.tag!("pxd", "paper-type" => "A4", "orientation" => "landscape", "title" => "出力タイトル", "xmlns:xlink" => "http://www.w3.org/1999/xlink"){
xml.tag!("page"){
xml.tag!("svg", "width" => "29.7cm", "height" => "21cm", "viewBox" => "0 0 2970 2100"){
xml.tag!("style", "type" => "text/css"){
xml.cdata "\
.col1 { x:200; dy:100;}\
.col2 { x:400;}\
.col3 { x:600; text-anchor:end;}\
}
xml.tag!("text", "y" => "500", "font-size" => "40"){
for sample in @samples
xml.tag!("tspan", "class" => "col1"){
xml.text! sample.field1
}
xml.tag!("tspan", "class" => "col2"){
xml.text! sample.field2
}
xml.tag!("tspan", "class" => "col3"){
xml.text! sample.field3
}
end # for loop
} # text
} # svg
} # page
}# pxd
|
の様にして出来ました。
xml << '<?xml version="1.0" encoding="utf-8"?>' は、xm.instruct! で行けるはずなんですが、うまく出力されず、生のステートメントを書いています。もっとも、どっちにしろテスト環境ではうまくレイアウトされますので、問題は無いんですが。
.rxml テンプレートファイルには、Builder::XmlMarkupが用いられるのですが、これがどう便利なんだか、私にはぜんぜん判っていません。
上記のようにした場合、ページのオーバーフローは無視されます。そこで、出力した行数を数えて、基準を超えたら改ページをさせたいところですが、XmlMarkup でどう実現するのか、しばら〜く悩みました。pagination と組み合わせようかとも思ったのですが、結局、改ページさせたいところで
if rowcounts >= 15
xml << "</text></svg></page>"
xml << "<page>"
xml << '<svg x="0" y="0" viewBox="0 0 2970 2100" height="21cm" width="29.7cm">'
xml.tag!("style", "type" => "text/css"){
xml.cdata "\
.col1 { x:200; dy:100;}\
.col2 { x:400;}\
.col3 { x:600; text-anchor:end;}\
}
xml << '<text font-size="40" y="500">'
rowcounts = 1
end
|
みたいな感じで <page> を挟んで対処しました。
う〜ん。【xml <<】使うくらいなら、XmlMarkup 要らない気がするのは私だけ?
でも、render :text => とかするよりは.rxml テンプレート使った方が判りやすいですよね、きっと……。
ああ、サンプルにスタイルシート入っていて見にくいですね。別に xml.cdata 使わなくても OK ですので。
上であげたサンプルコードは、実際に私が試したものとは異なります。このままで動くかどうかは保証の限りではありません。詳細については、それぞれのマニュアルなり、ヘルプページなりを参照して下さい。
使ってみれば、PXDoc は結構便利そうです。罫線も引けるし、網掛けも出来るし。グラフはまだ未挑戦です。後でやってみようかな。
|
|