railsでcsv出力したいときありますよね。
どういう方法でやろっかなーとザッとググってみたら、csv生成をcontroller内に直接書いたりModelにメソッド定義してModel.to_csv(records)
みたいなかんじでやってるコードが結構出てきます。
けど、csvもhtmlやjsonなんかと同じようにviewで書いたほうがなんかスッキリする気がしたのでやってみました。
class UsersController < ApplicationController
def index
@users = User.all
respond_to do |format|
format.html do
@users = @users.page params[:page]
end
format.csv do
send_data render_to_string, filename: "users-#{Time.now.to_date.to_s}.csv", type: :csv
end
end
end
end
require 'csv' # initializersとかに書いたほうがいいかも
CSV.generate do |csv|
cols = {
'ID' => ->(u){ u.id },
'姓名' => ->(u){ "#{u.last_name} #{u.first_name}" },
'性別' => ->(u){ u.sex },
'誕生日' => ->(u){ u.birthday.strftime('%Y年%m月%d日') },
'所持金' => ->(u){ number_to_currency u.money }
}
# header
csv << cols.keys
# body
@users.each do |user|
csv << cols.map{|k, col| col.call(user) }
end
end
# csvダウンロードへのリンクはこんなかんじで
= link_to 'Download CSV', users_path(format: :csv)
viewのテンプレートを.ruby
として素のrubyで書いて、controller側でrender_to_string
で文字列としてとってきてsend_data
でレスポンスとして投げつけてます。
controller側はformat.csv
だけでも大丈夫なんですが、今回はファイル名を指定したかったのでこんなかんじに。
今回は標準ライブラリのCSV
で書きましたが、テンプレートを素のrubyで書くので自分の好きなように書けるのはなかなかいいんでないかと。
あと、別の表示項目のcsvも必要だなーと思ったらその分view書いてから、action増やすなりrenderするview分けるなりでどんどん増やしやすい&Modelなんかに直接書くより見通しがいいんでないかと思います。
投稿してから、同様のものが既出だと気づいたけど、気にしないことにしました