2008-09-18 102 views
52

我有一個名爲「項」的簡單數據庫表:,如何返回記錄爲CSV文件

class CreateEntries < ActiveRecord::Migration 
    def self.up 
    create_table :entries do |t| 
     t.string :firstName 
     t.string :lastName 
     #etc. 
     t.timestamps 
    end 
    end 

    def self.down 
    drop_table :entries 
    end 
end 

我如何寫一個處理程序將返回條目表的內容爲CSV文件(理想情況下它會自動在Excel中打開)?

class EntriesController < ApplicationController 

    def getcsv 
    @entries = Entry.find(:all) 

    # ??? NOW WHAT ???? 

    end 

end 
+0

至少在最近版本的Rails,你也可以用`進入這樣做。全部`而不是。 – 2010-09-29 00:47:23

回答

22

有一個名爲FasterCSV的插件可以很好地處理這個問題。

+29

請注意,ruby> = 1.9,FasterCSV現在是標準的CSV庫,並且被稱爲CSV。 – kdt 2011-01-25 17:23:41

+0

關鍵是`require'csv'`,請參閱https://ruby-doc.org/stdlib/libdoc/csv/rdoc/CSV.html – mb21 2017-02-24 08:46:57

7

看看FasterCSV寶石。

如果您只需要支持excel,那麼您可能還會考慮直接生成xls。 (見表格:: Excel)中

gem install fastercsv 
gem install spreadsheet-excel 

我發現這些選項適合在Windows Excel中打開CSV文件:

FasterCSV.generate(:col_sep => ";", :row_sep => "\r\n") { |csv| ... } 

至於ActiveRecord的部分,像這樣的事:

CSV_FIELDS = %w[ title created_at etc ] 
FasterCSV.generate do |csv| 
    Entry.all.map { |r| CSV_FIELDS.map { |m| r.send m } }.each { |row| csv << row } 
end 
2

您需要在響應中設置Content-Type標頭,然後發送數據。 Content_Type:應用程序/ vnd.ms-excel應該可以做到。

您可能還需要設置Content-Disposition標頭,使其看起來像一個Excel文檔,並且瀏覽器選擇一個合理的默認文件名;這就像Content-Disposition:附件;文件名=「#{建議名} .xls」

我建議使用fastercsv ruby​​ gem來生成您的CSV,但也有一個內置的csv。該fastercsv示例代碼(來自創業板的文檔)看起來是這樣的:

csv_string = FasterCSV.generate do |csv| 
    csv << ["row", "of", "CSV", "data"] 
    csv << ["another", "row"] 
# ... 
end 
+0

感謝那些晦澀難懂的Content-Type!我實際上並不確定它最終會不會是Excel,但這很好理解。 – Eric 2008-09-18 17:28:49

87

FasterCSV肯定是要走的路,但如果你想直接從您的Rails應用程序服務於它,你要設置一些響應標題也是如此。

我養的方法周圍設置文件名和必要的標頭:

def render_csv(filename = nil) 
    filename ||= params[:action] 
    filename += '.csv' 

    if request.env['HTTP_USER_AGENT'] =~ /msie/i 
    headers['Pragma'] = 'public' 
    headers["Content-type"] = "text/plain" 
    headers['Cache-Control'] = 'no-cache, must-revalidate, post-check=0, pre-check=0' 
    headers['Content-Disposition'] = "attachment; filename=\"#{filename}\"" 
    headers['Expires'] = "0" 
    else 
    headers["Content-Type"] ||= 'text/csv' 
    headers["Content-Disposition"] = "attachment; filename=\"#{filename}\"" 
    end 

    render :layout => false 
end 

使用,可以很容易有這樣的事情在我的控制器:

respond_to do |wants| 
    wants.csv do 
    render_csv("users-#{Time.now.strftime("%Y%m%d")}") 
    end 
end 

而且有一個觀點看起來像這樣:(generate_csv來自FasterCSV)

UserID,Email,Password,ActivationURL,Messages 
<%= generate_csv do |csv| 
    @users.each do |user| 
    csv << [ user[:id], user[:email], user[:password], user[:url], user[:message] ] 
    end 
end %> 
+0

嗯,我以爲我完成了,直到我看到你的答案!感謝您的頭部細節,我會記住那些以防萬一到目前爲止我遇到麻煩。 – Eric 2008-09-18 17:27:36

+8

如上所述,FryCSV在ruby 1.9及更高版本中只是CSV。 gererate_csv方法現在是CSV.generate。 – 2011-08-10 01:24:14

+4

在generate_csv/CSV.generate塊的末尾添加.html_safe將使其正確處理數據中的任何逗號。沒有這個調用,我的csv文件裏面有一堆" "。 – stcorbett 2011-10-10 20:07:03

24

我接受了(並投票贊成!)@布萊恩的回答,首先指向我的FasterCSV。然後,當我搜索到寶石時,我還在this wiki page找到了一個相當完整的例子。把它們放在一起,我解決了下面的代碼。

順便說一句,安裝寶石的命令是: sudo的創業板安裝fastercsv (全部小寫)

require 'fastercsv' 

class EntriesController < ApplicationController 

    def getcsv 
     entries = Entry.find(:all) 
     csv_string = FasterCSV.generate do |csv| 
      csv << ["first","last"] 
      entries.each do |e| 
       csv << [e.firstName,e.lastName] 
      end 
      end 
      send_data csv_string, :type => "text/plain", 
      :filename=>"entries.csv", 
      :disposition => 'attachment' 

    end 


end 
24

另一種方式來做到這一點,而無需使用FasterCSV:

要求紅寶石的CSV初始化文件中的庫,如config/initializers/dependencies.rb

require "csv" 

由於某些背景下面的代碼是基於創建搜索資源的Ryan Bate's Advanced Search Form。在我的情況下,搜索資源的顯示方法將返回以前保存的搜索結果。它也響應csv,並使用視圖模板來格式化所需的輸出。

def show 
    @advertiser_search = AdvertiserSearch.find(params[:id]) 
    @advertisers = @advertiser_search.search(params[:page]) 
    respond_to do |format| 
     format.html # show.html.erb 
     format.csv # show.csv.erb 
    end 
    end 

的show.csv.erb文件如下所示:

<%- headers = ["Id", "Name", "Account Number", "Publisher", "Product Name", "Status"] -%> 
<%= CSV.generate_line headers %> 
<%- @advertiser_search.advertisers.each do |advertiser| -%> 
<%- advertiser.subscriptions.each do |subscription| -%> 
<%- row = [ advertiser.id, 
      advertiser.name, 
      advertiser.external_id, 
      advertiser.publisher.name, 
      publisher_product_name(subscription), 
      subscription.state ] -%> 
<%= CSV.generate_line row %> 
<%- end -%> 
<%- end -%> 

在報告頁上我有一個導出鏈接,用戶正在查看報告的HTML版本。以下是返回該報告的CSV版本的link_to:

<%= link_to "Export Report", formatted_advertiser_search_path(@advertiser_search, :csv) %> 
2

以下走近我的情況下工作良好,導致瀏覽器下載後打開的CSV類型相應的應用程序。

def index 
    respond_to do |format| 
    format.csv { return index_csv } 
    end 
end 

def index_csv 
    send_data(
    method_that_returns_csv_data(...), 
    :type => 'text/csv', 
    :filename => 'export.csv', 
    :disposition => 'attachment' 
) 
end 
0

如果你只是想自己從控制檯獲得CSV數據庫,你可以在幾行

tags = [Model.column_names] 
rows = tags + Model.all.map(&:attributes).map(&:to_a).map { |m| m.inject([]) { |data, pair| data << pair.last } } 
File.open("ss.csv", "w") {|f| f.write(rows.inject([]) { |csv, row| csv << CSV.generate_line(row) }.join(""))}