RubyXLを使ってExcelを編集してクライアントに返す
railsでエクセルを編集してクライアントに返そうとしたときのやり方を残しておきます。
作るもの
- クライアントがエクセルファイルをアップロードする
- サーバが受け取ったエクセルに何かしらの変更を加える
- クライアントが変更されたファイルをダウンロードする
といった動きになる機能をRailsで作ります。 出来上がったソースコードはこちら。
GitHub - ytnk531/excel-example: rails excel example
Excelの編集
RubyXLというgemを使います。
他にもエクセルを開けるgemはあるのですが、
- Roo: 読み込みのみ
- AXSLX: 新規作成のみ
という感じで用途が絞られています。 今回は、編集ができるRubyXLを使います。
単体だと、以下のような感じで使えます。
require 'rubyXL' # ファイルを読み込んでRubyXL::Workbookにデシリアライズ workbook = RubyXL::Parser.parse("path/to/Excel/file.xlsx") # ブック→シート→行→セルという構造になっている worksheet1 = workbook[0] row1 = worksheet1[0] cell1 = row1[0] # 書き込むときはWorksheetのメソッドが使える worksheet1.add_cell 0, 0, 'changed' # 保存 workbook.save
rails new
railsプロジェクトを作ります。 今回は横着してモデルを作らないので、ActiveRecordなどいらないモジュールを生成しないようオプションを付けます。
rails new -MOCJ
ルーティング
excelリソースへのルートを作ります。 加えて、ルートをexcelsにします。
下記とおりルーティングされます
- GET / -> ExcelsController#show
- GET /excels -> ExcelsController#show
- POST /excels -> ExcelsController#create
GET /excelsでファイルを受け取るフォームを表示し、POST /excelsでサーバへのファイルアップロードと編集後ファイルの送信を行います。
Rails.application.routes.draw do # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html root to: "excels#show" resource :excel, only: [:show, :create] end
excel-example/routes.rb at master · ytnk531/excel-example · GitHub
コントローラ
showメソッドでは何もせず、ページを表示するだけです。 createにはエクセルファイルが送られて来るので、ファイルの編集とクライアントへの送信を行います。
class ExcelsController < ApplicationController def show end def create file = params[:file] # ファイルを開く workbook = RubyXL::Parser.parse file.path # 編集する workbook[0].add_cell 0, 0, 'changed' # 編集したファイルを送る send_data workbook.stream.string, type: file.content_type, filename: 'modified.xlsx' end end
アップロードされたファイルはActionDispatch::Http::UploadedFileオブジェクトとして受け取ることができます。 tempfileに受け取ったファイルそのものが入っているので、RubyXLオブジェクトに変換します。
編集したファイルは、send_dataメソッドを使って送信します。
データとして渡すのは、Workbook#streamで取得できるバイナリのストリームを、Stream#stringで文字列にしたものです。 コンテントタイプを指定する必要がありますが、UploadedFileは受信したときのContent-Typeを記録しているので、同じものを指定しておけばいいでしょう。
excel-example/excels_controller.rb at master · ytnk531/excel-example · GitHub
ビュー
エクセルファイルをアップロードするためのビューを作ります。
<%= form_tag({action: :create}, multipart: true) do %> <div> <%= file_field_tag :file %> </div> <div> <%= submit_tag "Send" %> </div> <% end %>
https://github.com/ytnk531/excel-example/blob/master/app/views/excels/show.html.erb
ファイル選択と送信ができます。 送信したファイルはExcelsController#createで処理します。
試してみる
このようなファイルを用意し、
送ってみます。
編集されたファイルのダウンロードが始まります。
開いてみます。期待通り編集されたエクセルをダウンロードできました。
まとめ
- RubyXLでエクセルの編集ができる
- アップロードされたファイルはUploadedFileオブジェクトに記録される
- RubyXLで保存したワークブックは、保存しなくてもデータ送信できる
UploadedFileの存在を知らなかったので、うまくいくかわからなかったのですが、うまくrailsと一緒に使うことができました。