Instead of displaying the xml file rendered by the index.api.rsb file in my browser, i want to download it. To me this sounds very simple, but I cant find a solution.
I tried the following in the controller-method:
def split
if params[:export] == "yes"
send_file *here comes the path to xml view*, :filename => "filename", :type => :xml
end
respond_to ...
end
The result is a MissingFile exception...
Thanks in advance
Note that :disposition for send_file defaults to 'attachment', so that shouldn't be a problem.
If you have a MissingFile exception, that means the path is incorrect. send_file expects the path to an actual file, not a view that needs to be rendered.
For your case, render_to_string might be what you need. Refer to this related question. It renders the view and returns a string instead of setting the response body.
def split
if params[:export] == "yes"
send_data(render_to_string path_to_view, filename: "object.xml", type: :xml)
end
end
To force it to download it, add :disposition => attachment to your send_file method.
Source: Force a link to download an MP3 rather than play it?
Related
I am generating a PowerPoint using the powerpoint gem and up until now I was using send_file, but now I want to use send_data. The reason for this is that send_data blocks the application from doing anything else until the call completes, while send_file allows the app to continue executing while the file downloads, which sometimes, due to coincidental timing, leads to the file being deleted before the user tells their browser to start the download and the web server finishes sending the file and thus a blank or incomplete file is downloaded.
This is how I create my PowerPoint:
#Creating the PowerPoint
#deck = Powerpoint::Presentation.new
# Creating an introduction slide:
title = 'PowerPoint'
subtitle = "created by #{username}"
#deck.add_intro title, subtitle
blah blah logic to generate slides
# Saving the pptx file.
pptname = "#{username}_powerpoint.pptx"
#deck.save(Rails.root.join('tmp',pptname))
Now, on to what I have tried. My first instinct was to call as follows:
File.open(Rails.root.join('tmp',"#{pptname}"), 'r') do |f|
send_data f.read, :filename => filename, :type => "application/vnd.ms-powerpoint", :disposition => "attachment"
end
I've also tried sending the #deck directly:
send_data #deck, :filename => pptname, :disposition => "attachment", :type => "application/vnd.ms-powerpoint"
Reading it ends with a larger file than expected and it isn't even able to be opened and sending the #deck results in a PowerPoint with one slide that simply has the title: #Powerpoint::Presentation:0x64f0dd0 (aka the powerpoint object).
Not sure how to get the object or file into binary format that send_data is looking for.
You need to open the file as binary:
path = #deck.save(Rails.root.join('tmp',pptname))
File.open(path, 'r', binmode: true) do |f|
send_data f.read, filename: filename,
type: "application/vnd.ms-powerpoint",
disposition: "attachment"
end
This can also be done by calling the #binmode method on instances of the file class.
send_data #deck, ...
Will not work since it calls to_s on the object. Since Powerpoint::Presentation does not implement a #to_s method you're getting the default Object#to_s.
I am trying to download a file filled with a string. However, no matter which way I try, the file ends up blank.
Here is the relevant code:
def export(notes)
stream = render_to_string(:template=>"cards/export.enex.erb", :locals => {:notes => notes}, :formats => [:enex])
send_data(stream.to_s, :filename => "notes.enex")
end
I have been using Rails.logger.info to try to track down the problem and have confirmed that stream is not empty and (when prompted to) my log shows that the file was sent full of the correct data. I am using a custom mime type (enex) and that is all set up correctly in config. I've tried several different methods and nothing works. Here are some other attempts:
(1)
#notes = notes
render file: "cards/export", formats: [:enex], type: 'text/plain', disposition: 'attatchment; filename=cards.enex'
(2)
render template: "cards/export", formats: [:enex], :locals => {:notes => notes}, type: 'text/plain', disposition: "attatchment", filename: "notes.enex"
(3)
send_file 'app/views/cards/export.enex.erb', type: 'application/enex', disposition: "attachment; filename=notecards.enex", :x_sendfile=>true
In each case, the file ends up blank.
As you can see, the string I am using is created by filling out an erb form. If it matters, "notes" is a hash that I use to fill out the form. I know how to get this to work by using a button on a view and a respond_to in the controller but I am purposely not using the database and would prefer to solve the problem using a private controller method as shown.
I am using Rails 4
Can you see anything that would cause the send_data to fail?
Try using send_file but instead of giving it the path to the erb, give it the path to the file you generated with that template and specify the type as application/xml or text/xml. I don't have experience with enex files, but I think this may simplify the issue.
file = "my_file.enex"
File.open(file, "w") do |f|
f << render_to_string(:template=>"cards/export.enex.erb", :locals => {:notes => notes}, :formats => [:enex])
end
send_file(file.path, type: "application/xml")
In Rails 3 AttachmentsController, I have the following:
def show
attachment = Attachment.find_by_id(params[:id])
redirect_to(attachment.authenticated_url())
end
Where authenticated_url is simply a URL to S3 to access the file.
The problem is that the file is always downloaded by the browser. What I would like to have happen is if the file is an image/pdf, something the browser can render, show the file in the browser and only download non-browser friendly files.
Have you seen this before? Any ideas on where to start?
Thanks
send_file can be used for remote url as well
file = open("http://cdn2.example.com/somefile.pdf")
send_file(file, :filename => "example.pdf", :type => "application/pdf" , :disposition => "attachment")
Here example.pdf will be downloaded. If you want open pdf in browser itself use this
file = open("http://cdn2.example.com/somefile.pdf")
send_file(file, :filename => "example.pdf", :type => "application/pdf" , :disposition => "inline")
redirect_to #attachment.url
I'm using Paperclip as well, and this display pictures inside the browser. Do you have to do something different than this?
I think you'll want to look into the rails send_file method.
1) http://apidock.com/rails/ActionController/DataStreaming/send_file
The :disposition option lets you decide whether a file will be downloaded or displayed inline. I used this in my rails app to let users download mp3 files.
Hope this helps.
This is tough one to explain so i'll try my best, and hopefully edit the question if people need more information. I am not providing exact code, but merely an example of the issue.
I am using rails 2.3.8. I am on Unix.
I have a bunch of files under a directory not Apache accessible. (i.e. /data/files/file.rpk)
I have the following in my view.
link_to "RPK File", :controller => 'mycontroller', :action=> 'myaction', :file => '/data/files/file.rpk'
I have the following in my controller.
def myaction
if FileTest.exists?(params[:file])
render :file => params[:file]
end
end
When i select the link on the page i get a download prompt for my desired file, but the name of the file is "myaction" instead of the filename.
Thoughts on how i could get it named correctly?
Sounds like a job for send_file. The x_sendfile option prevents that your workers keep busy while transferring the actual file. You can read more about that in this blogpost.
send_file path_to_file_on_filesystem, :type => "application/zip", :x_sendfile => true
You want to use send_data with the :filename option. See the API documentation.
You want to be extremely careful with this, though. Never ever trust the client/user! They will send file=../../../../etc/group or something in order to read arbitrary files on your system, so be very sure to sanitize that value before passing it to any file-reading methods.
im working on a Rails project that should create XMl files, or to be more specific
use existing XMl templates and put content from the database in it.
So i dont need to create the xml structure, basically just rendering a template with content.
What would be the smartest way to do that?
So far i have a file.xml.erb in my layout folder
and i have a custom route "/renderXML" that does
def renderXML
#reading_question = ReadingQuestion.find(params[:id])
render :file => 'layouts/question.xml'
end
This works, but i also want to save the file, not only show it (actually viewing it is not really needed).
For saving i found this
File.open('fixed.xml','w'){|f| f.write builder.to_xml}
How do i access the rendered file and save it with some method like above?
Perhaps something like:
s = render_to_string :file => 'layouts/question.xml'
File.open('fixed.xml','w'){|f| f.write s}
render :text => s
Another approach :
send_data fixed, :type => 'text/xml; charset=UTF-8;', :disposition =>
"attachment; filename=fixed.xml"