Help us understand the problem. What is going on with this article?

Rails で CSV ファイルを View を使って生成する

More than 3 years have passed since last update.

利用明細、売上系のデータを、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 },
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away