在rails中,如何将记录作为csv文件返回
我有一个名为" 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
如何编写一个处理程序,以CSV文件形式返回Entries表的内容(理想情况下,它将以Excel自动打开的方式)?
class EntriesController < ApplicationController
def getcsv
@entries = Entry.find( :all )
# ??? NOW WHAT ????
end
end
解决方案
有一个名为FasterCSV的插件可以很好地处理此问题。
看看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
我们需要在响应中设置Content-Type标头,然后发送数据。 Content_Type:application / vnd.ms-excel应该可以解决问题。
我们可能还需要设置Content-Disposition标头,使其看起来像Excel文档,并且浏览器选择一个合理的默认文件名。类似于Content-Disposition:附件; filename ="#{suggested_name} .xls"
我建议使用fastcsv ruby gem生成CSV,但是也有内置的csv。 fastcsv示例代码(来自gem的文档)如下所示:
csv_string = FasterCSV.generate do |csv| csv << ["row", "of", "CSV", "data"] csv << ["another", "row"] # ... end
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 %>
我接受了(并投票赞成!)@Brian的答案,这是我第一次把我指向FasterCSV。然后,当我用谷歌搜索找到宝石时,我也在此Wiki页面上找到了一个相当完整的示例。将它们放在一起,我确定了以下代码。
顺便说一句,安装gem的命令是:
sudo gem安装更快
(全部小写)
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
另一种不使用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) %>

