在rails中,如何将记录作为csv文件返回

Eri*_*ric 55 csv ruby-on-rails

我有一个名为"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
Run Code Online (Sandbox Code Playgroud)

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

class EntriesController < ApplicationController

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

    # ??? NOW WHAT ????

  end

end
Run Code Online (Sandbox Code Playgroud)

Cli*_*ach 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
Run Code Online (Sandbox Code Playgroud)

使用它可以很容易地在我的控制器中有这样的东西:

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

并有一个看起来像这样的观点:( 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 %>
Run Code Online (Sandbox Code Playgroud)

  • 如上所述,FasterCSV在ruby 1.9及更高版本中只是CSV.gererate_csv方法现在是CSV.generate. (9认同)
  • 在generate_csv/CSV.generate块的末尾添加.html_safe将使其正确处理数据中的任何逗号.没有这个调用我的csv文件有一堆"&quot; 在里面. (4认同)

Eri*_*ric 26

我接受了(并投票了!)@ Brian的回答,首先指向我FasterCSV.然后当我用Google搜索找到宝石时,我在这个维基页面上也找到了一个相当完整的例子.把它们放在一起,我决定使用以下代码.

顺便说一句,安装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
Run Code Online (Sandbox Code Playgroud)

  • 我建议将CSV生成移动到视图中:这比您通常在控制器中想要的更多的表示逻辑. (5认同)

rwc*_*c9u 25

不使用FasterCSV的另一种方法:

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

require "csv"
Run Code Online (Sandbox Code Playgroud)

作为一些背景知识,以下代码基于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
Run Code Online (Sandbox Code Playgroud)

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 -%>
Run Code Online (Sandbox Code Playgroud)

在报告页面的html版本上,我有一个链接,用于导出用户正在查看的报告.以下是返回报告的csv版本的link_to:

<%= link_to "Export Report", formatted_advertiser_search_path(@advertiser_search, :csv) %>
Run Code Online (Sandbox Code Playgroud)

  • 此解决方案工作正常但我不得不将CSV.generate_line调用设置更改为:row_sep为nil.此更改会从响应中删除不需要的空行.代码:`<%= CSV.generate_line row,{:row_sep => nil}%>` (6认同)
  • 如果使用rails 3,请不要忘记使用`<%= CSV.generate_line(row).html_safe%>`以避免转义字符. (5认同)
  • 要添加到Wilson的注释中,Heroku(雪松堆栈-beta)将在csv文件中插入空行,除非您明确告诉它不要使用`:row_sep => nil`. (2认同)

Bri*_*ian 23

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

  • 请注意,ruby> = 1.9,FasterCSV现在是标准的CSV库,只是称为CSV. (30认同)

kch*_*kch 7

看看FasterCSV宝石.

如果你需要的只是excel支持,你也可以考虑直接生成xls.(参见电子表格:: Excel)

gem install fastercsv
gem install spreadsheet-excel
Run Code Online (Sandbox Code Playgroud)

我发现这些选项适合在Windows Excel中打开csv文件:

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

至于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
Run Code Online (Sandbox Code Playgroud)