docxファイルの生成・出力機能を開発する機会があったので、 pandoc-ruby を利用した実装方法について説明します。
なお、開発および動作確認はMacOS環境で行っています。
環境次第では本記事の内容が完全に再現できないかもしれません。ご了承ください。
gemについて
pandoc というドキュメントフォーマット変換のプログラムがあり、 pandoc-ruby
はそのRuby用ラッパーライブラリです。
このライブラリを利用する場合、まず出力内容を表すファイルや文字列を用意して、それを .docx
に変換する流れで実装していきます。
他のライブラリも探したのですが、GitHubのスター数で pandoc-ruby
に匹敵する代替案が見つからず、このgemを採用しました。
準備
コントローラーで format.docx
のように記述したいので、MIME typeを登録しておきます。
# config/initializers/mime_types.rb
Mime::Type.register "application/vnd.openxmlformats-officedocument.wordprocessingml.document", :docx
pandoc-ruby
が利用する pandoc
も必要なので、あらかじめインストールしておきます。
# Dockerfile
RUN apt install -yq\
pandoc\
...
Gemfileには pandoc-ruby
を追加します。
# Gemfile
gem "pandoc-ruby"
使用方法
例として、GETリクエストでファイルダウンロードを可能にしたい場合、以下のように実装します。
# audios_controller.rb
def show
respond_to do |format|
format.docx do
str = render_to_string "audios/show.docx.erb", locals: { audio: @audio }
document = PandocRuby.convert(str, to: :docx)
send_data document, filename: "audio_#{@audio.id}.docx", mime_type: Mime["docx"], disposition: :attachment
end
end
end
docxファイルは動的な内容にしたいので、変数埋込可能なerbテンプレートを利用して出力内容を表しています。
また、 pandoc
は入力内容をデフォルトでMarkdownとして解釈します。そのため、 PandocRuby.convert
の前に render_to_string
を呼び出し、 erbテンプレートの内容をHTML文字列(Markdownとして解釈可能な文字列)に変換しています。
直接確認していませんが、 pandoc
が扱えるものであれば、他のフォーマット同士でも PandocRuby.convert
で :from
/ :to
の指定・変換ができるはずです。
erbファイルは以下のようにしています。
<!-- audios/show.docx.erb -->
<% audio.transcripts.each do |transcript| %>
<%= transcript.started_at.strftime("%X") %>
<%= "" %>
<%= transcript.content %>
<%= "" %>
<br>
<%= "" %>
<% end %>
このテンプレートで、以下のようなdocxファイルを生成しています。
改行 / 改段落
注意点として、Markdown / docxには改行と改段落があり、見た目も異なります。
改行 | 改段落 |
---|---|
erbでは以下のように記述しています。
<!-- 改行 -->
<%= "\\" %>
<!-- 改段落 -->
<%= "" %>
空の段落
<%= "" %>
を連続させる方法が思いつきますが、これだと段落が1つにまとまり、空の段落は挿入されません。
<%= transcript.content %>
<%= "" %>
<%= "" %>
オフィシャルな解説が見つからなかったのですが、検証した限りでは「空の行 + 改段落」の組み合わせで空の段落を挿入できるようです。
自分は以下のように <br>
を挿入することで解決しました。
<%= transcript.content %>
<%= "" %>
<br>
<%= "" %>
簡単な内容でよければ、この程度の作業量でdocxファイルを生成することができます。