Rails3 axlsx でxlsxファイルを作成しダウンロードする

前の記事で課題だった部分を別のライブラリ(axlsx)を使って解決。
ただし、axlsxはエクセルの読み込みはできないため、都度書式等を作成することになる。
axlsxの日本語での情報が少ないので、参考になればと。
作成したコードの一部抜粋・改変のため、コピペでは動くかは確認していません。

機能

Rails でDBのデータをエクセルに帳票として出力
・ファイルはダウンロードできる
・エクセルはxlsx形式
・axlsxを利用
・スタイルの定義はモジュール化

  • index.html.rb
# coding: utf-8
# remote => true にするとこのままだと、ファイル選択ダイアログが表示されない。
<%= form_tag(url_for(:controller => 'export', :action => 'download'), :remote => false) do %>
  <%= submit_tag('ダウンロード') %>
<% end %>
  • export_controller.rb
# coding: utf-8
class ExportController < ApplicationController
  require 'axlsx'
  include TableStyle

  def download
    package = Axlsx::Package.new
    # 横幅の自動調整無効
    package.use_autowidth = false
    workbook = package.workbook
    # 印刷設定
    # fit_to_width:次のページ数に合わせて印刷(横)
    # orientation:印刷の向き 横
    # paper_size:紙の種類。数値はGitHub参照。9はA4
    setup = {:fit_to_width => 1, :orientation => :landscape, :paper_size => 9}
  
    # ワークシートの追加(name:シート名、page_setup:ページ設定)
    worksheet = workbook.add_worksheet(:name => "Example01", :page_setup => setup)
    # 列の横幅
    worksheet.column_widths(5, 5, 5, 15)
  
    # スタイルの定義(モジュール参照)
    cst = create_style(workbook)

    # 行の追加(関数も指定可)
    worksheet.add_row(["ABCD", nil, nil, "=SUM(D1:D2)"], :style => cst)
    # セル結合
    worksheet.merge_cells("A1:C1")

    file_name = "example.xlsx"
    # ファイルデータのダウンロード
    send_data(package.to_stream.read,
      :type => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
      :disposition => 'attachment', :filename => file_name)
  end
end
  • table_style.rb(lib/)
# coding:utf-8
module TableStyle

  def create_style(workbook)
    top_left = nil
    # 書式設定
    # bg_color:背景色
    # b:太字
    # u:下線
    # sz:文字サイズ
    # border:枠線
    #  edges:枠線を引く箇所。配列。複数指定化。(top,bottom,right,left)
    #  style:線種(thin:実践, medium:太線, dashed:破線 etc・・・)
    #  color:線の色。FFXXXXXX。
    # alignment:文字配置。(horizontal:横位置, vertical:縦位置)
    base = {:bg_color => "FF98fb98", :u => true, :b => true, :sz => 11, :border => {:edges => [:bottom], :style => :thin, :color => "FF333333"}, :alignment => {:horizontal => :center, :vertical => :center}}
    workbook.styles do |worksheet|
      top_left = worksheet.add_style(base)
      # 上下左右で異なる枠線を引く場合(そういうケースが多いのに方法が複雑・・・他に良い方法ありませんか?)。
      # 先の[border]-[edges]と被るとファイルが開けなくなる。
      lth = worksheet.borders[worksheet.cellXfs[top_left].borderId]
      lth.prs << Axlsx::BorderPr.new(:name => :left, :color => Axlsx::Color.new(:rgb => '333333'), :style => :medium)
      lth.prs << Axlsx::BorderPr.new(:name => :top, :color => Axlsx::Color.new(:rgb => '333333'), :style => :medium)
    end
    # 配列でadd_rowするセル各々に異なるスタイルを適用できる。(例A〜C列のセルにのみスタイル適用)
    return [top_left, top_left, top_left, nil]
  end
end
  • mime_types.rb(config/initializers/)
# 追記
Mime::Type.register 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', :xlsx
  • application.rb(config/)
# lib/ に置いたモジュールを読み込ませるために追記
config.autoload_paths += %W(#{config.root}/lib)
  • Gemfile
# 追記
gem 'axlsx'