LoginSignup
1
2

More than 1 year has passed since last update.

インチキをしてRailsでExcelを読み書きする

Posted at

Excel大好きな人達

多くの案件ではExcel好きなプロパーとかExcel好きなプロパーとかExcel好きなプロパーが跋扈しており、確固たる理由はないがなんとなく「Excelライクで」とか言われることが非常に多いと感じています。
Excelライクと言わないまでも、Excelをアップロードできたりダウンロードできたりと言った要件は、非常にカジュアルに生じています。

「DXの意味わかっているの?」と言いたくなるのですが、これが原状なのでしょうがありません。

Railsライブラリの限界

ただ、Railsエンジニアなら一度は経験したことがあると思うのですが、RailsにはExcelをうまく扱えるライブラリがあまりありません。

ライブラリ 機能 注記
Axlsx 新規作成から書き出しだけ 新規作成のみで、テンプレートファイルからの新規作成もできない。複雑なワークシートを作ろうと思うと、コードが恐ろしく読みにくくなる
Roo 読み込みだけ 読み込み専用
RubyXL 読み書き可能 数少ない読み書き可能なライブラリだが、parseが恐ろしく遅いのであまり使い物にならない

Pythonにはopenpyxlがある

一方、Pythonは世界中のデータサイエンティストが使っていることもあって、openpyxlという非常に使いやすいライブラリが存在して、ものすごく手軽に扱うことが可能になっています。
今回は、Rubyからopenpyxlを呼び出してみました。

コンテナにpython及びライブラリを入れる

今回はDockerを使っている前提で、Rubyの動いているコンテナにpythonをインストールします。システム管理やaws-cliを動かすためにすでに入っているケースも多いと思います。

Dockerfile
FROM ruby:2.7.4-alpine

RUN mkdir /app
ENV APP_ROOT /app
WORKDIR $APP_ROOT
RUN apk add --update --no-cache \
    ...
    python3 python3-dev py3-pip && \
    pip install openpyxl
...

コンテナを使っていない場合はvenvを使ったほうがいいと思いますが、本稿では触れません。

簡単なPythonスクリプトを作成する

ここでは、標準入力から{"A1": "Hello, World!"}のようなJSONを受け取り、テンプレートのExcelファイルに書き込んだうえ、そのExcelファイルを標準出力に書き出すスクリプトを作成しました。
メインのロジックをあまりRailsの外におきたくなかったので、極力シンプルにしています。

python/to_excel.py
import os
import sys
import json
import openpyxl
import tempfile

cell_values = json.loads(sys.stdin.read())

wb = openpyxl.load_workbook("spec/fixtures/template.xlsx")
ws = wb.worksheets[0]

for cell, value in cell_values.items():
    ws[cell] = value

tmp = tempfile.NamedTemporaryFile(delete=False)
wb.save(tmp.name)
tmp.close()

with open(tmp.name, 'rb') as f:
    sys.stdout.buffer.write(f.read())

os.unlink(tmp.name)

Ruby(Rails)からpopenでpythonを呼び出す

excel = IO.popen('python3 python/to_excel.py', 'r+') do |io|
  io.puts cell_values.to_json
  io.close_write
  io.read
end

excelにはExcelファイルのバイナリが入ります。ActiveStorageに入れるなり、send_dataするなりして料理しましょう。

1
2
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2