【Ruby on Rails】rails-latexを利用してPDFを作成

# はじめに
Ruby on Railsで個人開発をした際に、gem [rails-latex](https://github.com/amagical-net/rails-latex)を使って、ユーザーが入力したTeXコードをコンパイルしてPDFを作成する機能を実装しました。
関連する記事があまりなかったので、どのようにしたのかを残そうと思います。

# 設定
PDF作成には `LatexToPdf.generate_pdf(code, config)`メソッド（[rubydoc](https://www.rubydoc.info/gems/rails-latex/2.3.0/LatexToPdf.generate_pdf)）を利用するので、gemをインストール後、その設定を行います。初期設定は以下の通りです。
（注）「・・・」の部分は、`Users/・・・/(appのルートディレクトリ)`が入ります。

```
LatexToPdf.config
=> 
{:recipe=>[],         
 :command=>"pdflatex",
 :arguments=>["-halt-on-error"],
 :default_arguments=>["-shell-escape", "-interaction=batchmode"],
 :workdir=>
  #<Proc:0x00000001135d1830 /・・・/vendor/bundler/ruby/3.1.0/gems/rails-latex-2.3.4/lib/rails-latex/latex_to_pdf.rb:16 (lambda)>,
 :preservework=>false,
 :basedir=>"/・・・/tmp/rails-latex",
 :parse_runs=>1}
```

今回、platex, dvipdfmxを実行してTeXコードをPDFに変換するので、設定の `command` をそのように書き換えます（[Rails で LaTeX を使って帳票出力](https://tech.actindi.net/2014/11/17/3625190713)を参考にしました）。
config/initializers/rails_latex.rb
```
# frozen_string_literal: true

LatexToPdf.config[:command] = Rails.root.join("lib/tasks/platex_dvipdfmx.sh").to_s
```

lib/tasks/platex_dvipdfmx.sh
```
#!/bin/bash

platex -halt-on-error -shell-escape -interaction=batchmode input && dvipdfmx input
```

# TeXコードのコンパイル
ユーザーが入力したTeXコードをコンパイルしてPDFを作成します。

以下のコードは、渡されたcode（文字列）をコンパイルして、コンパイルが成功すればPDFのpathを、失敗すればログを返すコードです。
```
    # code をコンパイルする
    begin
      pdf_binary = LatexToPdf.generate_pdf(code, LatexToPdf.config)
      pdf_path = Rails.root.join("public/hoge/fuga.pdf")

      File.open(pdf_path, "w+b") do |f|
        f.write(pdf_binary)
      end

      render json: { url: pdf_path }　　# コンパイル成功時は pdf_path を返す
    rescue RailsLatex::ProcessingError => e
      render json: { log_text: e.log } # コンパイル失敗時はログを返す
    end
```
- `LatexToPdf.generate_pdf(code, config)`メソッドに`code`（文字列）と`config`を渡すと、PDFのバイナリ文字列が得られるので、これをPDFファイルにします。
- コンパイル失敗時には `RailsLatex::ProcessingError` 例外（[rubydoc](https://www.rubydoc.info/gems/rails-latex/2.3.0/RailsLatex/ProcessingError)）が発生し、その例外オブジェクト `e` から `e.log`でログのテキストを取得することができます。
参考：[READMEーException handling and debugging](https://github.com/amagical-net/rails-latex#exception-handling-and-debugging-)
この[issue](https://github.com/amagical-net/rails-latex/issues/35) にあるように、`e.message.scan(/\/.*\.log/).first`でログファイルのパスを取得し、これを利用する手もあります。

# 注意
READMEに以下のような記述があります。
> The last log file is moved to tmp/rails-latex/input.log , and the corresponding source TeX file to tmp/rails-latex/input.tex . If the PDF is not produced the build directory is not removed; an archive script should be written to occasionally clean up the tmp/rails-latex directory.

ログファイルとTeXのソースファイルは `tmp/rails-latex`に格納されますが、PDFが作成されない場合、削除されずに残り続けます。そのため、時々`tmp/rails-latex` ディレクトリをクリーンアップするスクリプトが必要です。

# herokuでの利用
herokuでTeXを利用ために、次のビルドパックを使いました。
[heroku-buildpack-tex](https://github.com/thermondo/heroku-buildpack-tex)
デフォルトで最新バージョンのTeX Liveがインストールされますが、TeX Liveをフルでインストールするとherokuのslugサイズの上限を簡単に超えてしまうため、必要最小限のものだけがインストールされます。そのため、必要なものがあれば自分で追加する必要があります。

[README-Custom packages](https://github.com/thermondo/heroku-buildpack-tex#custom-packages)にあるように、レポジトリのルートディレクトリに`texlive.packages`を作成し、そこに必要なものを記述します。
参考： [Heroku buildpack - Installing texlive binary package](https://stackoverflow.com/questions/13254558/heroku-buildpack-installing-texlive-binary-package)

今回、platex、フォント、tikzを利用するためのパッケージを追加して、以下のようにしました。
texlive.packages
```
jsclasses
platex
pgf
japanese-otf
haranoaji
haranoaji-extra
```


# 参考
- [Rails で LaTeX を使って帳票出力](https://tech.actindi.net/2014/11/17/3625190713)
- [LatexToPdf(rubydoc)](https://www.rubydoc.info/gems/rails-latex/2.3.0/LatexToPdf#generate_pdf-class_method)
- [Exception: RailsLatex::ProcessingError(rubydoc)](https://www.rubydoc.info/gems/rails-latex/2.3.0/RailsLatex/ProcessingError)
- [thermondo/heroku-buildpack-tex](https://github.com/thermondo/heroku-buildpack-tex#custom-packages)
- [Heroku buildpack - Installing texlive binary package](https://stackoverflow.com/questions/13254558/heroku-buildpack-installing-texlive-binary-package)