How to send json data without template? - ruby-on-rails

I am learning rails and trying to modify some existing code. The code in question calls a separate server to render a PDF which is downloaded from the browser.
I would like to change it to just download a json file instead when in development.
Chrome appears to download the file but says "Failed - network error". When I inspect the download it seems to have no body in the response.
The server shows:
Completed 200 OK in 77ms (Views: 0.6ms | ActiveRecord: 16.7ms)
My controller code looks like this:
# if in development, just send the json to check
if Rails.env.development?
send_data json.to_json, :filename => 'account_statement.json', :type => 'application/json', :disposition => 'attachment'
else
begin
send_data generate_report(json.to_json), :filename => 'account_statement.pdf', :type => 'application/pdf', :disposition => 'attachment'
rescue => e
raise 'Report server is not available, Please try again later'
end
end
Printing the json.to_json to the console does also show a json string, so that seems fine.
How can I debug this further?

Related

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

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"

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.

Integrate Jasper in Rails 3

I'm trying to integrate a rails 3 app with jasper following this wiki:
http://wiki.rubyonrails.org/rails/pages/HowtoIntegrateJasperReports
But it seems that a lot of information isn't updated so it's been very hard to make it work by myself. I've also read a topic at ruby-forum: http://www.ruby-forum.com/topic/139453
with some details explained but still couldn't make it work.
My first problem is related with the render_to_string method:
When the controller method runs I receive a "Template is missing" error:
this is the method:
def report
#customers = Customer.all
send_doc(render_to_string(:template => report_customers_path, :layout => false), '/pdfs', 'report.jasper', "customers", 'pdf')
end
Although this seems simple I'm not understanding why is this happening. Doesn't render_to_string with layout => false suposed to get me the string result of that action?
I also tried :action instead of :template, but it does the same.
If anybody with some expertise with this integration could help...
Thanks in advance,
André
We actually use jasperreports to create reports, and recently upgraded to Rails 3.0. To create the xml, we use xml.erb templates. Jasper reports runs in a separate glassfish server Here's the general idea:
url = URI.parse(my_url_string)
dataxml = render_to_string(:template => my_template_name).gsub(/\n/, '')
params = {'type' => 'pdf', 'compiledTemplateURI' => my_jasper_file, 'data' => dataxml }
request = Net::HTTP::POST.new(url.request_uri)
request.set_form_data(params)
obj = Net::HTTP.new(url.host, url.port)
obj.read_timeout = my_timeout_setting
response = obj.start { |http| http.request(request) }
case response
when Net::HTTPOK
send_data(response.body, :filename => my_chosen_filename, :type => "application/pdf", :disposition => "inline")
else
raise "failed to generate report"
end
I don't know anything about jasper, but it sounds like you want to do two things: render a PDF template and then send the raw output back w/ a PDF mime type:
pdf_contents = render_to_string(:template => 'users/report')
send_data(pdf_contents, :file_name => 'report.pdf', :type => 'application/pdf')
You're passing in the external URL as the template path, but that's probably wrong if you're getting errors about the template path. Fix the template path first.
Use savon to interact with jaserserver in rails3.
Here is an example:
require 'logger'
require 'savon'
logger = Logger.new(STDOUT)
logger.info "Test jasper via Savon-SOAP"
#client = Savon::Client.new {
wsdl.document = "http://localhost:8080/jasperserver/services/repository?wsdl"
http.auth.basic "jasperadmin", "jasperadmin"
}
logger.info "runReport method"
begin
result = #client.request :run_report do
soap.body = "<requestXmlString>
<![CDATA[
<request operationName='runReport' >
<argument name='RUN_OUTPUT_FORMAT'>PDF</argument>
<resourceDescriptor name='' wsType='' uriString='/reports/samples/AllAccounts' isNew='false'>
<label></label>
</resourceDescriptor>
</request>
]]>
</requestXmlString>"
end
send_data result.http.raw_body, :type => 'application/pdf', :filename => 'report.pdf', :disposition => 'attachment'
rescue Exception => e
logger.error "SOAP Error: #{e}"
end
Try to change the render_to_string() code to this:
#customers.to_xml

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