Rails - Force XML template to be downloaded instead of rendered - ruby-on-rails

My question is very similar to this question but that answer does not work for me. I have a custom xml file that I want downloaded instead of rendered by the browser. I've tried the send_file method like the answer to the question I linked above, but I also get an error can't convert Hash into String.
Controller:
respond_to do |format|
format.tmx
end
Template: show.tmx.erb
<?xml version="1.0"?>
<tmx xmlns="http://www.gala-global.org/oscarStandards/tmx/tmx14b.html" version="1.4b">
</tmx>
View (I want this link to download a document instead of render in the browser):
<%= link_to "Download", document_path(#document, format: "tmx") %>

You can use the send_file, however it would need to refer to another endpoint already setup supplying the content. Or if you don't use the xml in any other context you can use the following:
format.tmx { send_data render_to_string(:show), filename: 'file.tmx', type: 'application/xml', disposition: 'attachment' }
HTH,

Related

Is it possible to use send_data (not send_file) via ajax request in rails?

I have a link that downloads a dynamically generated file. The way I have it functioning is the following:
I created a custom controller action on a resource (created a custom route in routes.rb)
Clicking the link (non-ajax at this point) directs to this custom Controller action
The file is generated, and the last line in the custom controller action is send_data which streams the document to the user.
Update: It was recommended to include code. Here is the code in that custom controller action:
class MyController < ApplicationController
def custom_action_sending_pdf
pdf = InitMyPdf.new(#user)
send_data pdf.render, filename: "complete_report.pdf", type: "application/pdf"
end
end
The issue is that request.referrer for the next request will now reference this custom controller action, and I do not want it to do that. This is also reflected in the url.
This specifically becomes an issue when later in my app I redirect back to request.referrer. When the request.referrer is this custom controller action: it does not redirect to an actual page but instead just re-downloads the document all over again.
Instead I try this:
I make the link to that custom action an ajax request via the remote: true option
On one hand: the request.referrer now properly seems to not be referencing that controller action. However, now the file is not downloading!
I have done some looking around:
This question does not have an answer that can be immediately applied.
This question applies to downloading a static file which does not work for me because my file is dynamically generated, so I use send_data to send the generated file to the user as opposed to send_file.
Question: Ultimately I am trying to let a user download a dynamically generated file, all while NOT changing the page (keeping the request.referrer the same). Is this possible?
Update
I am aware of this question but the issue with it is that it's accepted answer is using send_file, and since my file is dynamically generated: send_file will not work for me here.
This works. use button_to
Example:
<%= button_to(<custom_action_sending_pdf_path>, method: :get, class: 'btn btn-primary') do %>
<i class="fa fa-print" aria-hidden="true"></i></i> Print PDF
<% end %>
Let that button go to that custom action which downloads the pdf (same code as in original question):
class MyController < ApplicationController
def custom_action_sending_pdf
pdf = InitMyPdf.new(#user)
send_data pdf.render, filename: "complete_report.pdf", type: "application/pdf"
end
end
What happens now is when that button is clicked:
The pdf downloads and pops up adobe (at least it does this in safari)
The url of the page does not change to the custom action which prints the pdf. So for the next request: request.referrer will not be that custom action for the pdf, which is the desired behavior here.

Generate XML file and redirect to other view with Rails

I have a piece of code that generates an XML file. What I want to, and didn't find the solution, is to generate the XML file and ALSO redirect to another page, to give a feedback message.
My code is
def exportFiles
#files=FileToExport.getComponentToExport
recursive_tree= GitHubRepositorioService.getRecursiveTree('master')
GitHubService.updateFiles(#files, recursive_tree)
xml = Builder::XmlMarkup.new(:target=>$stdout, :indent=>2)
respond_to do |format|
format.xml { send_data render_to_string(:exportFiles), filename: 'exported_module.xml', type: 'application/xml', disposition: 'attachment' }
end
FileToExport.setComponentToExport(nil)
end
As I already use "respond_to" I can't use another redirect sentence... so, there is a way to generate (downloading) that file and redirect to other view?
Unfortunately, this is not possible via the controller as you can't send two responses.
But you could do this via javascript for instance. See this topic for more info Rails how do I - export data with send_data then redirect_to a new page?

How to save a Prawn generated PDF to the public folder?

I'm using Prawn gem to generate PDFs In my application...
app/controllers/orders.rb
class OrdersController < ApplicationController
...
def show
respond_to do |format|
format.html
format.pdf do
require "prawn/measurement_extensions"
...
#render pdf document
send_data pdf.render,
filename: "order_#{#order.id}.pdf",
type: 'application/pdf',
disposition: 'inline'
end
end
end
...
end
And It's working fine for displaying, But My questions are..
How to -Automatically- save those generated pdfs in the public folder (folder for each day) after a successful order creation? I've tried searching Prawn Documentation But I've found nothing.
How to show orders in only pdf format? I've Tried to Comment the format.html line but It didn't work
When you call pdf.render and send it to the client with send_data, you're actually dumping the contents of the pdf over the wire. Instead of that, you could dump the result of pdf.render in a file with File.new and use send_file in the controller. Check the documentation for File. Alternatively, you could attach the generated pdf to the specific order using something like Paperclip.
If you generate the pdf as a file in the server, you should use send_file instead of send_data. Read more about this in the guides.
You can use Prawn's render_file method to save the generated PDF to a file:
pdf.render_file(Rails.root.join('public', "order_#{#order.id}.pdf"))
See documentation: https://prawnpdf.org/docs/0.11.1/Prawn/Document.html

Render PDF in Browser (instead of download default)

I store PDF receipts in S3. I use WickedPDF for generating the PDF files. Via the admin area of our app, there is a "Download" link, that is simply a direct link to the S3 path:
link_to "Download", order.receipt.url unless order.receipt.blank?
Any idea on how I can have it default to opening in a browser window instead of direct download?
The trick is to change the headers, if you link to a static file your webserver (S3) will add a header Content-Disposition: attachment; filename="name.pdf" without this header the browser will try to render this inline (same window).
To solve this issue you could have an action on your controller that downlaods the file itself and steams it to the user
require "open-uri"
class OrderController
def receipt
#order=Order.find(....)
render text: open(#order.receipt.url).read, content_type=>'application/pdf'
end
end
Obviously add a route to it identifying the order and link to this new action, this will render the pdf downloaded by rails without the 'attachment' header.
Render pdf:
render pdf: "Invoice",
orientation: 'Portrait',
template: "Invoice/download",
page_size: 'Letter'
If the PDF should be shown in a part of the page, you could use the following code on your page
<object data="<%= upload.file.url %>" width="100%" height="100%" style="min-height: 100%; height:100%; width:100%" type="<%= upload.mime_type %>">
<p>No PDF render functionality on your device...</p>
</object>
If you just want to show the PDF as a full page file, use this in your controller (creating a pdf on the fly)
pdf = #sales_invoice.pdf
send_data pdf.render, filename: "sales_invoice.pdf",
type: "application/pdf",
disposition: "inline"
use send_file method. This is the link that may help you.
http://apidock.com/rails/ActionController/Streaming/send_file

Rails download http response/displayed site

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?

Resources