,如何返回记录为CSV文件
我有一个名为“项”的简单数据库表:,如何返回记录为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
看看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:应用程序/ 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
感谢那些晦涩难懂的Content-Type!我实际上并不确定它最终会不会是Excel,但这很好理解。 – Eric 2008-09-18 17:28:49
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 %>
我接受了(并投票赞成!)@布莱恩的回答,首先指向我的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
另一种方式来做到这一点,而无需使用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) %>
以下走近我的情况下工作良好,导致浏览器下载后打开的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
一个不错的宝石,生成CSV看看的CSV整形宝石。
https://github.com/paulspringett/csv_shaper
它有一个很好的DSL和作品真的很好用Rails的模型。它还处理响应头并允许文件名自定义。
如果你只是想自己从控制台获得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(""))}
至少在最近版本的Rails,你也可以用`进入这样做。全部`而不是。 – 2010-09-29 00:47:23