【问题标题】:Streaming CSV Download from Rails 3.2 app从 Rails 3.2 应用程序流式下载 CSV
【发布时间】:2012-04-10 03:31:43
【问题描述】:

我迫切希望在我的 Rails 3.2.2 应用程序中获得流式 CSV 下载。

我已经尝试过'csv_builder' gem (https://github.com/dasil003/csv_builder),它宣传支持此功能,但似乎 Rails 3.2 中有一些更改使其无法正常工作(它会在应用启动时产生“未初始化的常量 ActionView::Template::Handler”错误)。

还有其他想法或解决方案吗?谢谢!

编辑:为了澄清,我需要将模型的所有条目导出为 CSV 文件。有这么多行,它正在超时......因此需要流式传输。我过去曾为此使用过 Comma gem (https://github.com/crafterm/comma),但目前它也不支持流式传输。

【问题讨论】:

  • 你想达到什么目的?一些示例代码可能会有所帮助。

标签: ruby-on-rails ruby ruby-on-rails-3 csv streaming


【解决方案1】:

好的,经过更多研究后,我在控制器中将以下内容组合在一起。如果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
  }

【讨论】:

  • 您能否提供完整的控制器定义以确保
  • 这只是让我想用相同的代码让它与 Rails 3.2.1 一起工作。除了“listen 3000, :tcp_nopush => false”之外,独角兽配置是否还有其他内容?除了您在上面发布的代码之外,我可能还缺少什么?任何额外的见解都会很棒,非常感谢。
  • 如果你使用了 Rack::ETag,你需要添加下面一行来防止 ETag 缓冲响应:self.response.headers["Last-Modified"] = Time. now.to_s
  • 也可以查看本教程:jacopretorius.net/2014/02/…
【解决方案2】:

我对 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

views/exports/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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多