55

我有一个名为“Entries”的简单数据库表:

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

如何编写一个将 Entries 表的内容作为 CSV 文件返回的处理程序(理想情况下,它会自动在 Excel 中打开)?

class EntriesController < ApplicationController

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

    # ??? NOW WHAT ????

  end

end
4

10 回答 10

89

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 %>
于 2008-09-18T17:21:41.153 回答
27

我接受(并投票!)@Brian 的回答,首先将我指向 FasterCSV。然后当我用谷歌搜索找到 gem 时,我还在这个 wiki 页面上找到了一个相当完整的示例。将它们放在一起,我确定了以下代码。

顺便说一下,安装gem的命令是:sudo gem install 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
于 2008-09-18T17:24:32.193 回答
26

不使用 FasterCSV 的另一种方法:

在 config/initializers/dependencies.rb 之类的初始化文件中需要 ruby​​ 的 csv 库

require "csv"

作为一些背景,以下代码基于Ryan Bate 的创建搜索资源的高级搜索表单。在我的例子中,搜索资源的 show 方法将返回之前保存的搜索结果。它还响应 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) %>
于 2008-10-21T17:16:04.517 回答
23

有一个名为 FasterCSV 的插件可以很好地处理这个问题。

于 2008-09-18T17:07:43.840 回答
7

查看FasterCSV gem。

如果您只需要 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
于 2008-09-18T17:08:03.310 回答
2

您需要在响应中设置 Content-Type 标头,然后发送数据。Content_Type: application/vnd.ms-excel 应该可以解决问题。

您可能还想设置 Content-Disposition 标头,使其看起来像 Excel 文档,并且浏览器会选择一个合理的默认文件名;这类似于 Content-Disposition: attachment; 文件名="#{建议名称}.xls"

我建议使用 fastcsv ruby​​ gem 来生成你的 CSV,但也有一个内置的 csv。fastcsv 示例代码(来自 gem 的文档)如下所示:

csv_string = FasterCSV.generate do |csv|
  csv << ["row", "of", "CSV", "data"]
  csv << ["another", "row"]
# ...
end
于 2008-09-18T17:16:28.547 回答
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
于 2012-06-22T00:02:32.117 回答
1

尝试一个不错的 gem 从 Rails https://github.com/crafterm/comma生成 CSV

于 2012-07-17T07:00:59.637 回答
0

看看 CSV Shaper gem。

https://github.com/paulspringett/csv_shaper

它有一个很好的 DSL,并且与 Rails 模型配合得非常好。它还处理响应标头并允许自定义文件名。

于 2012-07-25T19:15:21.813 回答
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(""))}
于 2013-07-19T01:25:36.017 回答