I am very new to ruby. I have a question that how can I export two files within one click.
In the exsiting version, I can generate only one file at a time by calling 'def stream_csv', but when I try to call it twice in order to get two files, I got an error indicating about "ActionController::DoubleRenderError (Can only render or redirect once per action):" I guess, it is because of render.
Here is the source code of stream_csv:
def stream_csv
require 'fastercsv'
filename = params[:action] + ".csv"
#this is required if you want this to work with IE
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}\""
controller.response.headers["Content-Transfer-Encoding"] = "binary"
end
render :text => Proc.new { |response, output|
csv = FasterCSV.new(output, :row_sep => "\r\n")
yield csv
}
end
end
Is it possible to create two files under one click? If yes, how can I do it?
You're right, it's because of render
. When you're setting headers
, and then finally call render
, you're building up an HTTP response to be sent to the browser. You can't do this twice from one HTTP request, which is why you get the ActionController::DoubleRenderError
.
One way to send multiple .csv
files at once is to combine them into a single .zip
file and send that instead of the raw .csv
files. There is an excellent, very easy to use rubyzip
gem you can use to build your .zip
file.
Instead of calling render inside stream_csv
, you can simply return the FasterCSV
instance itself or it's String output. From the calling method you can build up a .zip file (I'm not including code for that here since I'd just be copying and pasting from the README
at the gem above).
Finally, instead of setting so many headers to force the download, take a look at Rails send_file
method