Ruby(Rails)からExcelで文字化けしないCSVファイル作成

CSVファイル作成でハマったのでメモ。

今回作ろう思っていたのはリンクになっているボタンを押したらCSVファイルがダウンロードされるという単純なものです。

 

HTML載せようと思いましたがはてブ内での書き方わからないので省略、、

 

バージョンはRuby2.0, Rails4です。

 

controllerは下記のような感じで処理はmodelに。

# controllers/management_controller.rb

def event_csv
  respond_to do |format|
    format.csv { send_data Event.event_csv(start_date, end_date),
      :filename => "events_#{start_date}-#{end_date}.csv"
    }
  end
end

 もともとはここで:type => ""でcontent-typeをcsvと指定していたのですがそれではうまくいきませんでした。

 

modelは下記

# models/event.rb

class Event < ActiveRecord::Base
  class << self
    
    def event_csv(start_date, end_date)
      data = self.all
      csv_data = CSV.generate do |csv|
        csv << %w(ユーザー 所属 合計) # headerになる部分を先にpush
        data.each do |record|
          csv << [record[:username], record[:belonging], record[:sum]]
        end
      end
      
      csv_data
    end

  end
end    

 ここでもまだ文字コード指定はしていません。

CSV.generate自体ウェブ上にあまり情報がなくて、しかもdocumentを見るとgenerate('', :encoding => 'sjis')みたいな感じで:encodingで指定できるよ!って書いてあるのですが できませんでした。。(文字コードは上記の場合、csv_data.encodeで調べられます。)

 

なのでさらに戻ってcontrollerから最後吐き出すときにafter_filterでnkfを使ってShift_JISエンコードするという方法で解決しました。

 

class ApplicationController < ActionController::Base
  after_filter :cahnge_charset_to_sjis, :if => csv?
  
  ...
  
  private
    def csv?
      return request.original_url.match(/csv/) ? true : flase
    end
    
    def change_charset_to_sjis
      require 'nkf'
      
      response.body = NKF::nkf('-Ws', response.body)
      headers["Content-Type"] = "text/csv; charset=Shift_JIS"
    end    
  end
  
end

 

 パスがcsvだったらsjis文字コードを変えるメソッドを通してるって感じです。ここでheader["Content-Type"]も設定しています。

 

ちなみに念のためconfig/routes.rbにはこんな感じで書いてます。

get 'management/event_csv/(:start_date)/(:end_date)',  :to => 'management#event_csv'

 

controllerの中でrespond_toでcsvを指定しているので上記のパスに.csvでアクセスするとcsvファイルがダウンロードされる、という感じです。(ex. /management/event_csv.csv

 

文字化けは相変わらず辛い・・・。

うまく行かなかったところはもうちょい追求しなければ。

もっと良い実装があればぜひコメント下さい!m(_ _)m