Rails send_file/send_data - Cannot Read File - After web service call - ruby-on-rails

My Rails 3.1 app makes a web service call to get a pdf file that I then need to send to the browser for download.
The XML response is something like this:
<RenderResponse>
<Result>blahblah this is the file info<Result>
<Extension>PDF</Extension>
<MimeType>application/pdf</MimeType>
</RenderResponse>
I am then trying to convert the "Result" tag to a file as so:
#report = #results[:render_response][:result]
#report_name = MyReport.pdf
File.open(#report_name, "w+") do |f|
f.puts #report
end
finally I try to send to the browser:
send_file File.read(#report_name), :filename => #report_name, :type => "application/pdf; charset=utf-8", :disposition => "attachment"
This yields an error the says "Cannot Read File" and it spits out all the text from the results tag.
If I use send_data as so:
send_data File.read(#report_name).force_encoding('BINARY'), :filename => #report_name, :type => "application/pdf; charset=utf-8", :disposition => "attachment"
The download works but I get a file with 0KB and an Adobe Error that says the file "MyReport.pdf" can't be opened because "its either not a supported file type or it has been damaged".
How can I take the XML response file info, create the file, and stream to the browser?

I found the solution. send_file is the correct stream mechanism to use but I needed to decode the string while writing to the file. I also need to add the 'b' parameter to the File.open call.
This works:
File.open(#report_name, "wb+") do |f|
f.puts Base64.decode64(#report)
end
#file = File.open(#report_name, 'r')
send_file #file, :filename => #report_name, :type => "application/pdf; charset=utf-8", :disposition => "attachment"

Related

Firefox does not Show PDF File Extension on Download

I'm using rails to send a pdf back to the client and in Firefox the file extension is not showing:
My rails code looks like this:
send_data(
pdf,
:type => "application/pdf",
:disposition => "attachment; filename=transcript_#{Time.zone.now.strftime('%m-%d-%Y %H:%M')}.pdf",
# :filename => "transcript_#{Time.zone.now.strftime('%m-%d-%Y %H:%M')}.pdf"
)
I've been trying to set the file name with a combination of the :filename and :disposition key to display the correct filename in the browser. The :filename key doesn't seem to work in Firefox and the :disposition key gives me the picture above.
What do I need to change to get the pdf file extension to be shown in Firefox?
The space (inside of the time format) is throwing off the file name. You need to surround the file name in quotes.
Try this:
:disposition => "attachment; filename=\"transcript_#{Time.zone.now.strftime('%m-%d-%Y %H:%M')}.pdf\"",
^^ ^^
This behavior is explained here: http://kb.mozillazine.org/Filenames_with_spaces_are_truncated_upon_download.
The key point being that
[The space] creates an ambiguity when parsing the header for the filename when the browser has to consider the possibility of internationalized filenames. As Internet Explorer does not have to worry about this, it will parse the filename until the end of the line. Mozilla will not.
this will definitely work
send_data pdf.render, filename: 'transcript_#{Time.zone.now.strftime('%m-%d-%Y %H:%M')}.pdf',
type: 'application/pdf',
disposition: "attachment"

Ruby on Rails - send_file is not working

I wrote the following code.
def help_doc
pdf_filename = File.join(Rails.root, "/public/doc.pdf")
send_file(pdf_filename, :filename => "doc.pdf" :type => "application/pdf", :diposition => "inline")
end
It's working, but not as I want. I'd like to view in the browser the pdf, but it's doing download of the document.
I thought that just writing :disposition => "inline" and I could see on the browser the pdf.
Try removing the content disposition. You have a typo in your code, deposition vs disposition, and you're missing a comma after filename.

How to handle csv download prompt through a post request in Rails

I have a servlet (java) returning a csv file. So in my controller I send a post request,
def handleCsvRequest
response = RestClient.post theUrlPathTotheServlet queryParams
end
Now how do I handle the response so that it prompts the user to download this csv file. I know you can do this via a form and hidden Iframe but i'd like to do it through rails. I am looking through fastercsv but i am not finding great examples. Many thanks.
I have tried the following:
i have tried the following
csv_string = RestClient.post url, json, :content_type => :json
csv_file = CSV.generate do |csv|
csv << [csv_string]
end
send_data csv_file, :type => 'text/csv; charset=iso-8859-1; header=present', :disposition => "attachment; filename=report.csv"
but i don't get prompt for a file download? any ideas?
Do have a look at
1> http://fastercsv.rubyforge.org/ - For Documenation
2> http://supriya-surve.blogspot.com/2010/02/using-fastercsv-to-import-data.html - As an e.g.
Use send_file or send_data to send the csv data back to the browser.
A typical example of send_data is something along the lines:
csv_data = CSV.generate do
# block to generate CSV text
end
send_data csv_data, :filename => 'your_data.csv'
A typical example of send_file is
#csv_filename ="#{RAILS_ROOT}/tmp/your_data.csv"
send_file #csv_filename, :filename => "your_data.csv"
This should work in development. If this does not work in production, and you are using an Apache server,
you have to comment out the following line in config/environments/production.rb
config.action_dispatch.x_sendfile_header = "X-Sendfile"
Hope this helps.

rails send_file and send_data sends out zero byte files

I'm trying to send a pdf back to the user but I'm having serious problem getting send_file and send_data to work. I created the pdf file as follows:
tmp = Tempfile.new('filled')
new_tmp_path = PDFPrint.fill_form_using_pdftk(template_path, tmp.path)
send_file (new_tmp_path, :filename => 'filled.pdf')
The browser prompts for a download, but the downloaded filled.pdf file has zero byte.
I have verified that new_tmp_path does contain a valid pdf (good, filled content)
I have tried this:
File.open(new_tmp_path, 'r') do |f|
send_data(f.read, :filename => "filled.pdf")
end
But this also gives me the same download->zero-byte problem, while the file on server (new_tmp_path) has perfect content.
Regards,
Try sending a simple file to see if it works
send_file '/path/to.jpeg', :type => 'image/jpeg', :disposition => 'inline'
Read this thread, I think it has everything you need.

Difficulty with send_data in Ruby on Rails in conjunction with Spreadsheet plug-in

I have a function in a controller that takes in some specifications and generates a report on them. This function user_report is called in a view:
< %= submit_to_remote 'submit-button', "Export Report to Excel", :url => { :controller => :reports, :action => :user_report, :print_state => 'print'} % >
In reports_controller I use the Spreadsheet plugin to generate an Excel file within the user_report function. I want to use send_data to stream the file to the user without creating it on the server first. The research I've done shows that using StringIO is the way to go, as shown below. Frustratingly, nothing happens when I call send_data. The plugin seems to work well creating a file and saving it on the server, but does nothing when I use send_file, suggesting that the problem doesn't lie in the plugin. But then what am I doing wrong with send_file/send_data?
The function itself looks like this:
def user_report
if request.post?
unless params[:reports][:userid].blank?
#userid=params[:reports][:userid]
end
if params[:print_state]=='print'
report = Spreadsheet::Workbook.new
info = report.create_worksheet :name => 'User Information'
info.row(1).push 'User ID', #userid
#outfile = "Report_for_#{#userid}.xls"
require 'stringio'
data = StringIO.new ''
report.write data
send_data data.string, :type=>"application/excel", :disposition=>'attachment', :filename => #outfile
end
respond_to do |format|
format.js { }
end
end
end
The log file reads
2010-10-18 14:13:59 INFO -- Sending data Report_for_jjohnson.xls
but no download begins in-browser. I've succeed in using send_data on this app before, which is confusing.
I'm using Rails v2.3, Ruby v1.8.7, and Spreadsheet v6.4.1 at spreadsheet.rubyforge.org.
Just change the line:
send_data data.string, :type=>"application/excel", :disposition=>'attachment', :filename => #outfile
to:
send_data data.string.bytes.to_a.pack("C*"), :type=>"application/excel", :disposition=>'attachment', :filename => #outfile
Even though I dont like to write and delete , but with spreadsheet seems like the only solution.
# write the file
book.write "Employee_History_#{ params[:id]}.xls"
# send the file
send_file "Employee_History_#{ params[:id]}.xls", :type => "application/vnd.ms-excel", :filename => "data.xls", :stream => false
# and then delete the file
File.delete("Employee_History_#{ params[:id]}.xls")
For someone looking at this in (or after) 2022, a possible solution to this would be to use Axlsx Gem. The interface provides a method for converting it to a StringIO object. (From Axlsx Documentation)
#serialize to a file
p = Axlsx::Package.new
# ......add cool stuff to your workbook......
# Serialize to a stream
s = p.to_stream()
send_data(
s.read,
:type => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
:disposition => 'attachment',
:filename => #filename
)

Resources