

データベースにあるデータをいじってからCSVに出力したく、以下を参考に実装しました。  
<http://qiita.com/yutackall/items/24a4487f629a9106a971>

その際、サイズが小さい場合は大丈夫ですが、数千件になると発行されるSQLも多くなり、  
ダウンロードの準備ができるまで時間がかかります。  
（ダウンロードボタンを押してからSQLの発行が全て終わるまでに30分くらい）  
サイズが小さい場合はダウンロードできるのですが、大きい場合はSQLの発行が終わってもブラウザにダウンロードされません。（何も起きない）

クライアントでタイムアウトしているのではないかと思い、以下を参考にストリーミング配信にしよと思い実装しました。  
<http://qiita.com/regonn/items/76fc256d48e4d77c95ef>

そうすると、ダウンロードを押してもSQLが走らなく、空のデータになってしまいます。  
どこが問題でしょうか。コードを載せます。また、Apache+Passengerで動かしています。

[code]

    class OutputController < ApplicationController
      def download
        self.response.headers["Content-Type"] ||= 'text/csv; charset=Shift_JIS'
        self.response.headers["Content-Disposition"] = "attachment;filename=export_#{Time.now.to_i}.csv"
        self.response.headers["Content-Transfer-Encoding"] = "binary"
        self.response.headers["Last-Modified"] = Time.now.ctime.to_s
        @input = Input.find(params[:id])
    
        self.response_body = Enumerator.new do |yielder|
          @input.baseurls.find_each do |baseurl|
            @baseurls = baseurl
            yielder << (render :content_type => 'text/csv')
          end
        end
      end
    end
    
[/code]

この場合ですと@baseurlsには1000件のデータが入り、それをViewのdownload.csv.rubyに渡して1000件ずつ処理をしたいという感じです。download.csv.rubyでCSV.generateしています。


CC BY-SA 3.0
2016-04-30T04:29:14.490
24466
2020-07-25T06:28:13.740
2016-04-30T06:00:13.080
15334
15334
question
ruby-on-rails ruby
Ruby on Railsでサイズの大きいCSVのストリーミング配信について


一番目の参照記事から推測すると、この`render`で巨大なCSVを作成すると推測しています。その場合、`render`自体の実行が終わるまではボディーのデータは一切流れません。そのため、CSV作成に時間がかかると、ボディーのデータが来ないとしてタイムアウトを起こして、ボディーが空で処理されてしまっているのではないかと思います。`yielder
<< (render :content_type => 'text/csv')`部分を`yielder <<
@baseurl.to_s`とか適当に変えた場合と比較してみてください。

解決方法ですが、ストリーム配信にする場合、そもそも一番目の参照記事にあるようなCSV.generateで文字列を作る方法は使えません。この記事の方法はCSV作成を一度にやってしまうという作りだからです。ちゃんとストリームにするには、`yielder`にCSVを一列ずつ流し込んで行く必要があります。実際のやり方は下記の記事が参考になるでしょう。

<https://moreta.github.io/ruby/rails/rails-stream-download.html>

※ もしかしたら`CSV.new(yielder)`でも可能かも知れませんが、試していません。

もしくは、CSVは別途作成してから、ダウンロードする仕組みに変更するかです。Rails 6以上ならActive
Storageと組み合わせるといいと思われます。


CC BY-SA 4.0
2020-07-25T06:28:13.740
68936
2020-07-25T06:28:13.740
7347
24466
answer