railsにCSV形式でのダウンロード機能を追加する

背景

webアプリケーションの作成時に、「一覧データをExcelで開きたい」という要望をよく伺います。

そこで本記事ではrailsアプリにデータの一覧をcsv形式でダウンロード出来る機能を追加する方法について解説します。

モデルの変更

まずはモデルにCSV形式のデータを返却するメソッドを定義します。
今回は例として商品(Item)モデルを扱い、商品モデルは商品名と価格のカラムを持つということにします。

CSVファイルを扱うには、標準のCSVパッケージを使うのが簡単です。
ファイルサイズが巨大(例えば 100Mバイト以上)で無ければ性能的にも問題ないでしょう。

require 'csv'
class Item < ActiveRecord::Base
  def self.to_csv
    headers = %w(ID 商品名 価格 作成日時 更新日時)
    csv_data = CSV.generate(headers: headers, write_headers: true, force_quotes: true) do |csv|
      all.each do |row|
        csv << row.attributes.values_at(*self.column_names)
      end
    end
    csv_data.encode(Encoding::SJIS)
  end
end

CSV生成時のオプションとして、headersおよびwrite_headersでヘッダー行書き込みを、force_quotesで全てのフィールドの作成時にクオートを追加することを指定しています。
また、Excelで開くことを想定して#encodeメソッドでShift JISの文字コードを指定しています。

コントローラーにformat指定を追加

次にコントローラーにCSV形式での返却指定を追加します

class ItemsController < ApplicationController
  def index
    @items = Item.all
    respond_to do |format|
      format.html
      format.csv { send_data Item.to_csv, type: 'text/csv; charset=shift_jis', filename: "items.csv" }
    end
  end

respond_toブロック内部にformat.csvを追加することで、アドレス末尾に.csvを指定されたとき(例えばlocalhost:3000/items.csv)の動作を規定します。

CSV形式を指定した場合は直接ダウンロードさせたいので、send_dataを用いています。

ビューにダウンロードのリンクを張る

最後にダウンロード用のリンクを用意します。

= link_to 'CSV形式でダウンロード', items_path(format: 'csv')

コントローラーのindexメソッドにcsvでの返却を追加したのでitems_pathを指定し、そこにformat: 'csv'を渡すことでアドレス末尾に.csvを指定する場合と同じ動作をさせています。