利用明細、売上系のデータを、CSV でダウンロードする機能が必要になったので、
色々調べて実装した時のメモ。
色々調べると、モデルに self.to_csv
とクラスメソッド作ってやってるのが多かったんだけど、
「CSV 出力 ( 何の attribute を出力する云々 ) は View の責務だろ!!!!!!」と思い、
Rails4 から View のテンプレートに .ruby
が使えるようになったので、それを利用して View で出力するように実装。
利用イメージは、下記 URL にアクセスすると、csv のダウンロードが開始するイメージ。
http://hoge.hogehoge.com/sales/:target_month/donwload.csv
:target_month
はダウンロードする対象の月(YYYYMM)が入る。
routes.rb
には、URL から :target_month
として、params で受けられるよう記述
config/routes.rb
Hoge::Application.routes.draw do
resources :sales, only: [] do
collection do
get ':target_month/download', to: 'sales#download'
end
end
end
app/controllers/sales_controller.rb
class SalesController < ApplicationController
def download
@sales = Sales.target_month(params[:target_month]) # 対象月の売上を取得
respond_to do |format|
format.html { redirect_to :action => 'download', :format => 'csv' } # .csv がなくアクセスした場合はリダイレクト
format.csv { render :content_type => 'text/csv' }
end
end
end
CSV ファイルは、SHIFT-JIS じゃなきゃマズイだろうと思い、NKF で変換かけておく。
app/views/users/download.csv.ruby
require 'csv' # config/application.rb に書いてもいいけど、こっちにした
require 'nkf'
csv_str = CSV.generate do |csv|
# I18n で CSV のカラム名を取得
cols = {
Sales.human_attribute_name(:id) => ->(s){ s.id },
# 'ID' => ->(s){ s.id }, # key をそのまま指定する場合
Sales.human_attribute_name(:created_at) => ->(s){ s.created_at },
Sales.human_attribute_name(:sales_amount) => ->(s){ s.sales_amount },
Sales.human_attribute_name(:sales_tax) => ->(s){ s.sales_tax },
Sales.human_attribute_name(:sales_sum) => ->(s){ s.sales_amount + r.sales_tax },
}
# header の追加
csv << cols.keys
# body の追加
@sales.each do |sale|
csv << cols.map{|k, col| col.call(sale) }
end
end
# 文字コード変換
NKF::nkf('--sjis -Lw', csv_str)
もし、関連するモデルから値を取得したい場合も、いつもの記述方で法普通に取得できるのが便利
'ユーザー名' => ->(s){ s.user.name },