開発環境に使っているThin web serverにおいてsend_fileの呼び出し直後に、send_fileで送ったファイルを削除するとInternal serverエラーで止まる。
追記:本番環境(Apache + Passenger)の場合、Internal Serverエラーにはならないが、ダウンロードするファイルサイズが0 byteになる。
本文
あるページで、ボタンをクリックするとファイルのダウンロードが始まるページを作るとき、以下のようにするとWebRickではエラーとなり、Apache+passengerだとちゃんと動く。downloadsコントローラーのshowでボタンがクリックされると、downloads#csvfileが呼び出されてcsvファイルを一度作成し、それをsend_fileで送るというスクリプト。
app/views/downloads/show
<%= form_tag({:action => "csvfile"}, {:method => :get}) do -%> <%= submit_tag(_("ダウンロード開始")) -%> <% end -%>
app/controllers/downloads_controller.rb
def csfvile sourceAry = Array.new sourceAry.push(["hello", "world"]) sourceAry.push(["hello", "world, world!"]) filepath = "tmp.csv" CSV.open(filepath, "wb") do |writer| sourceAry.each do |line| writer << line end end if File.exist?(filepath) send_file(filepath, {:type => 'text/csv', :filename => "examinees_#{params[:id]}.csv"}) File.delete(filepath) # これがエラーを引き起こす end end
downloads#csvfile において、send_fileの終了後に作成したcsvファイルを削除しているのだけど、WebRickの場合エラーになる。Webブラウザ上の表示は「Internal server error」。ログのメッセージは以下のとおり。
!! Unexpected error while processing request: No such file or directory - /home/hogehoge/railsroot/tmp.csv
Happy Elements Labs:Rubyist必携 pry-railsを使いこなせば幸せになれるを参考に、pry-debuggerで逐次実行してみたところ、def csvfile の終了後にエラーが発生していることがわかった。エラーの理由は実際にファイルを送ろうとしたときに、そのファイルが存在していないため。つまり、send_fileを呼び出したときにファイルの送信が行われているのではないということ。
本番環境として使っているApache + passenger ではこのエラーは起こらない。
解決法がわからないけどとりあえずメモ。