Rails つまみぐい

Rails つまみぐい

Ruby on Rails 初学者による行き当たりばったりなメモ

axlsx (gem) で xlsx ファイルをダウンロード

Ruby on Rails v3.2.11
axlsx v1.3.4


いい加減そろそろ Excel2003 形式 (.xls) で出力し続ける理由がなくなってきてしまったので(^_^;、ようやく重い腰をあげて Excel2007 形式 (.xlsx) で出力に移行することにしました。使えそうなライブラリはないかと gem を探してみました。とりあえず目についた以下の3つをさわってみました。

3つを試してみた印象

roo は xls と xlsx の両対応という触れ込みで、No.1候補か!?と思ったんですが、xls部は spreadsheet に丸投げのようで、xls部とxlsx部とで書き方の作法がまるで違って、別々のものを使っても大して変わらない… さらに独自に作成されたxlsx部は、cell, row, column といったクラスがなく常に番地(行番号・列番号)でアクセスするという具合で、なんかかっちょ悪い感じがしました。(使用者の感想です)

他の2つ、acts_as_xlsx と axlsx は同じ作者によるライブラリのようで rails で使うなら acts_to_xlsx がおすすめと書いてありました。たとえば

Posts.where(created_at > Time.now-30.days).to_xlsx

みたいに、モデルからfindした結果をそのまま xlsx 化する場合には便利なようです。

ただ今回の自分の用途としては、表のヘッダー(表頭・表側)に色をつけたり複数のセルの結合 (merge) をしたりしたかったので axlsx でいくことにしました。

※ xlsx ファイルの書き出しのみで、現時点では読み込みには対応していない模様。
※ グラフを書いたりピボットテーブルを作ったりといったこともできるみたいです。

axlsx で xlsx ファイルを書き出す

基本的な使い方は、

  1. 新しいpackageを作り
  2. packageの中のworkbookに新しいworksheetを追加
  3. worksheetに1行ずつ追加
  4. package.to_stream.readで得られるデータをsend_dataで書き出す

といった感じです。

pkg = Axlsx::Package.new
pkg.workbook do |wb|
  wb.add_worksheet(:name => 'シート名') do |ws|   # シート名の指定は省略可
    ws.add_row ['a', 1]
    ws.add_row ['b', 2]
  end
end
send_data(pkg.to_stream.read, 
  :type => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
  :filename => "test.xlsx")


実際にダウンロードさせる際にはMIMEタイプの設定(config/initializers/mime_types.rb)も必要ですので忘れずに。

Mime::Type.register 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', :xlsx

もうちょっと細かく出力データを調整する

書式を指定する

書式の指定は、シート毎に add_style でスタイルを登録して、add_row する際に登録したスタイルを一緒に指定します。追加する行まとめて1つの書式を指定することもできますし、配列で1セルずつ指定してセル毎に書式を変えることも可能です。書式を指定しないか nil を指定するとデフォルトの書式になります。

my_style = ws.styles.add_style
             :fg_color=> "FF00000",
             :bg_color => "FFF0E6BE",
             :b => true,
             :sz => 14,
             :border => {:style => :thin, :color => "FF333333"},
             :alignment => {:horizontal => :center, :vertical => :center}

# 1行まとめて書式設定
ws.add_row ['a', 'b', 'c'], :style => my_style
# セルごとに書式設定
ws.add_row ['d', 'e', 'f'], :style => [my_style, nil, nil]


色の指定について

色は16進数でのRGB表示の頭に "FF" をつけて指定する。赤(#FF0000) ⇒ "FFFF0000"、黒: #000000 ⇒ "FF000000" といった具合。ちなみにRGBの各値が同じ場合は2桁の数字で省略できる。

my_style = ws.styles.add_style
             :fg_color=> "FF000000",
             :border => {:style => :thin, :color => "33"}  # "FF333333"と同じ


0パディングを維持する(セルの型を設定する)

セルの型は何も指定しないとデフォルトで Excel の「標準」型になります。基本的にはデータの値にあわせて自動的に型を判別してくれます。

date_format = ws.styles.add_style :format_code => 'YYYY-MM-DD'
time_format = ws.styles.add_style :format_code => 'hh:mm:ss'
ws.add_row ["Date", "Time", "String", "Boolean", "Float", "Integer"]
ws.add_row [Date.today, Time.now, "value", true, 0.1, 1],
             :style => [date_format, time_format]


ただし、"0016" など0でパディングされた数字列は数字として解釈されてしまい、そのまま add_row すると 16 となってしまいます。そんなときは add_row をするときに types を一緒に設定すればOKです。

ws.add_row ['0016']
# ws.rows.last.cells[0].value = 16

ws.add_row ['0016'], types => [:string]
# ws.rows.last.cells[0].value = "0016"

types は styles とは別に指定します。

date_format = ws.styles.add_style :format_code => 'YYYY-MM-DD'
ws.add_row ['2013/03/20'], styles => date_format, types => :date

(style の中にも type という別のプロパティがあるので注意)

型として使用できる値は :date、:time、:float、:integer、:string、:boolean の6つです。