我迫切希望在我的Rails 3.2.2应用程序中使用流式CSV下载。
我已经尝试了'csv_builder'gem(https://github.com/dasil003/csv_builder),它宣传了对此功能的支持,但似乎Rails 3.2中有一些变化使其无法正常工作(它会在应用启动时产生“未初始化的常量ActionView :: Template :: Handler”错误。
还有其他想法或解决方案吗?谢谢!
编辑:为了澄清,我需要将模型的所有条目导出为CSV文件。有很多行,它是超时的...因此需要流式传输。我过去曾使用过逗号宝石(https://github.com/crafterm/comma),但此刻它也不支持流式传输。
答案 0 :(得分:7)
好的,经过一番研究后,我在控制器中将以下内容混为一谈。如果给response_body
一些可枚举的东西(这是一个单词吗?),它会流。此外,服务器需要能够流(我在Heroku上使用Unicorn)。我非常想在控制器中没有所有这些东西,所以我的下一步是以某种方式提取出来。
format.csv {
@entries = Entry.all
@columns = ["First Name", "Last Name"].to_csv
@filename = "entries-#{Date.today.to_s(:db)}"
self.response.headers["Content-Type"] ||= 'text/csv'
self.response.headers["Content-Disposition"] = "attachment; filename=#{@filename}"
self.response.headers["Content-Transfer-Encoding"] = "binary"
self.response_body = Enumerator.new do |y|
@entries.each_with_index do |entry, i|
if i == 0
y << @columns
end
y << [entry.first_name, entry.last_name].to_csv
end
end
}
答案 1 :(得分:0)
我使用Rails 2.3.8应用程序的方法是生成一个新线程来处理csv解析,然后使用AJAX调用检查服务器以查看文件是否已准备好(我依赖于File.mtime )。
刚刚将其从应用中删除以发布此处,因此我删除了很多的csv解析代码,并且未包含所有视图
抱歉当天结束了:D
控制器/ exports_controller.rb
class ExportsController < ApplicationController
require 'fastercsv'
require 'generic_agent'
require 'generic_record'
def listing
@this_filepath = "../html/whatever/" << Time.now.strftime("%I:%M:%S_%d:%m:%y") << ".csv"
@spawn_id = spawn(:nice => 1) do
FasterCSV.open(@this_filepath, "w") do |csv|
csv << [ "outbreak_id"]
end
end
render :update do |page|
page.replace_html 'export_status', :partial => 'export_status_partial'
end
end
def send_export
@this_filepath = params[:with]
csv_file = File.open(@this_filepath.to_s, 'r')
csv_string = ""
csv_file.each_line do |line|
csv_string << line
end
send_data csv_string, :filename => "export.csv",
:type => 'text/csv; charset=iso-8859-1; header=present',
:disposition => "attachment; filename=export.csv"
#send_file @this_filepath.to_s, :stream => false, :type=>"text/csv", :x_sendfile=>true
#send_data csv_string, :filename => export.csv
#File.delete(@this_filepath.to_s)
end
def export_checker
filename_array = params['filename'].split(/\//)
@file_found = 0
@file_ready = 0
@file_size = File.size(params['filename'])
@this_filepath = params['filename']
if File.exists?(params['filename'])
release_time = Time.now - 5.seconds
if File.mtime(params['filename']).utc < release_time.utc
@file_found = 1
@file_ready = 1
@file_access_time = File.mtime(params['filename'])
@file_release_time = release_time
@file_size = File.size(params['filename'])
else
@file_found = 1
@file_ready = 0
@file_size = File.size(params['filename'])
end
else
@file_found = 0
@file_ready = 0
@file_size = File.size(params['filename'])
end
render :action => "export_checker"
end
end
视图/出口/ export_checker.rjs
if @file_found == 1 && @file_ready == 1 && @file_size > 0
page.replace_html 'link_to_file', :partial => "export_ready"
if @file_release_time
page.replace_html 'notice', "<div>Completed #{@file_release_time.strftime("%I:%M:%S %A %d %B %Y")} :: file size #{@file_size.to_s}</div>"
end
page.visual_effect :highlight, 'link_to_file', :endcolor => '#D3EDAB'
elsif @file_found == 1
page.replace_html 'link_to_file', "<div> File found, but still being constructed.</div><div>#{@this_filepath.to_s}</div>"
page.visual_effect :highlight, 'link_to_file', :endcolor => '#FF9900'
else
page.replace_html 'link_to_file', "<div> File not found @file_found #{@file_found.to_s} @file_ready #{@file_ready.to_s}</div>"
page.visual_effect :highlight, 'link_to_file', :endcolor => '#FF0000'
end