I have the option in my app to render a XML version of an invoice. To do this, I use a separate class, because it has some complicated calculations. This works fine and it renders the XML nicely in the browser.
However, I prefer to have it downloaded as file instead. How can I achieve this?
In the controller I now have this:
def show
#invoice = Invoice.find(params[:id])
respond_to do |format|
format.xml { render xml: #invoice.render_xml }
end
end
I know you can add options to get it downloaded:
filename: 'mydoc.xml', type: "application/xml", disposition: 'attachment'
But how do I combine it with my specific code?
Change render in your controller to send_data, and add the options that you have in your question. http://api.rubyonrails.org/classes/ActionController/DataStreaming.html#method-i-send_data
Related
I have a Rails controller which provides both HTML and PDF responses, and thus I have view.pdf.haml and view.html.haml files. These are either identical or extremely close to identical.
How can I have Rails use a single view for multiple formats?
You can specify what format to render with :formats option:
# Both will render view.html.haml
respond_to do |format|
format.html { render :view }
format.pdf { render :view, formats: :html }
end
https://guides.rubyonrails.org/layouts_and_rendering.html#the-formats-option
Do you mean have the same action serve up different resource types - i.e. both a web page and a PDF? If I understand the problem, you can use the respond_to method.
def show
#object = Object.find params[:id]
respond_to do |format|
format.html
format.pdf { ..code to render the pdf.. }
end
end
That ..code to render the pdf.. is the tricky part. There are PDF gems that support inline rendering, but you may end up using send_data or similar to set a file name, disposition, etc and deliver the PDF document to the end user.
I am using devise in my ruby on rails application.
I am calling following endpoint from a laptop web browser
https://myaddress/users/sign_in
It works well, but when I hit the same endpoint in mobile device it sends the request with header accept as Accept: image/*;q=0.8
Now server responds with 406 not acceptable. How can I force devise gems to accept request which may contain header accept with value image/*;q=0.8
I am not sure why you want to respond to an endpoint requesting an image, but it seems to me that you're looking for respond_to. See also this answer.
I'd guess you want to respond to "any". To support image MIME types, you can find an example here (emphasis mine):
If you need to use a MIME type which isn't supported by default, you
can register your own handlers in config/initializers/mime_types.rb as
follows.
Mime::Type.register "image/jpg", :jpg
respond_to also allows you to specify a common block for different
formats by using any:
def index #people = Person.all
respond_to do |format|
format.html
format.any(:xml, :json) { render request.format.to_sym => #people } end end
In the example above, if the format is xml, it will render:
render xml: #people
Or if the format is json:
render json: #people
any can also be used with no arguments, in which case it will be used
for any format requested by the user:
respond_to do |format| format.html format.any { redirect_to
support_path } end
Formats can have different variants.
I want to send an XML file when get request is made
here is my my xml file
<forms>
<form url="https://opendatakit.appspot.com/formXml?formId=CascadingSelect">Cascading Select Form</form>
<form url="https://opendatakit.appspot.com/formXml?formId=widgets">Widgets</form>
</forms>
this is my url
http://localhost:3000/forms/formlist
here is my ruby controller to send a xml
respond_to :xml
def formlist
respond_to do |format|
format.xml {//what should I write here to send formlist.xml}
end
end
here is route.rb
get 'forms/formlist' => 'forms#formlist'
but its not sending xml file giving error code something 422
Please help me
Thanks in advance.
Add .xml to url: http://localhost:3000/forms/formlist.xml
Then simply render your file:
def formlist
respond_to do |format|
format.xml { render '/path/to/formlist.xml' }
end
end
Instead of adding .xml to url you can write your route as this:
get 'forms/formlist' => 'forms#formlist', defaults: { format: 'xml' }
so every request without MIME type will be interpreted as xml request
respond_to do |format|
format.xml {//what should I write here to send formlist.xml}
end
You don't have to write anything between the braces--if your xml file has the correct name.
The route:
First, your route can be simply:
get "forms/formlist"
By default, rails assumes that a route has the format controller/action.
The action:
Your formlist() action can simply look like this:
def formlist
respond_to :xml
end
The respond_to line is a shortcut for:
respond_to do |format|
format.xml {}
end
In either case, your action will only respond to requests for an xml file; requests for other file types will produce an UnknownFormat error.
The view:
Then create the xml file here:
app/views/forms_controller/formlist.xml.erb
If you don't have any ruby code in your xml file, you can omit the .erb extension.
The url:
To request the xml file, you can use the url:
http://localhost:3000/forms/formlist
...and specify the following header in the request:
Accept: text/xml
For instance:
curl --header 'Accept: text/xml' http://localhost:3000/forms/formlist
Or, as rubykid posted, you can use the url:
http://localhost:3000/forms/formlist.xml
For instance:
curl http://localhost:3000/forms/formlist.xml
In either case, rails understands that the request is asking for an xml file.
respond_to():
By default, an action renders an html file named:
app/views/some_controller/action_name.html.erb
The default rendering can be changed with respond_to() and/or render().
For example, respond_to :xml will render the file:
app/views/some_controller/action_name.xml.erb
...which in your case will be:
app/views/forms_controller/formslist.xml.erb
If you want to render a different xml file, only then do you need to use the block form of respond_to() and write something inside the braces:
respond_to do |format|
format.xml {render ...}
end
In that case, see the Rails Guide on rendering for what you can do with render().
For completeness sake, the shortcut:
respond_to :xml, :json
...is equivalent to:
respond to do |format|
format.xml {}
format.json {}
end
Another option:
If the xml file is a static file, i.e. its content never changes, and you want to make it publicly available to anybody, you can put it in the public/ folder. For instance, if you name the xml file:
public/data.xml
...then anyone can request the xml file with the url:
http://localhost:3000/data.xml
I got wicked_pdf working, but one of the render options is file_name which as far as I can tell has no bearing at all on the PDF rendering. Can someone explain to me what exactly this is for?
class ThingsController < ApplicationController
def show
respond_to do |format|
format.html
format.pdf do
render :pdf => "file_name"
end
end
end
end
It is ultimately passed to Rails' send_data method as the filename option, which:
:filename - suggests a filename for the browser to use.
So when you say:
format.pdf { render pdf: 'the_answer' }
It becomes:
send_data(pdf_content, :filename => 'the_answer.pdf',..
The send_data method uses this (with other options) to set the Content-Disposition header in the response. If you inspect the response (e.g. in Chrome's Developer Tools) you will see:
Content-Disposition:inline; filename="the_answer.pdf"
How the browser implements this is ultimately up to it, but in Chrome you can see it by right clicking on the PDF and clicking 'Save as...'
Note: The presence of the :pdf key is used to decide whether wicked_pdf should handle it, so it must be specified if you wish you use this render helper.
This is probably more a design or usage question but the main issue is using the Prawn plugin with Rails 2.3.4 and accessing the resulting PDF object to render it to a file.
The scenario is basically;
a controller with the respond_to block setup
a view with code for rendering the text, graphics etc to PDF
It looks like:
From Customer Controller
def show
#customer = Customer.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #customer }
format.pdf { render :layout => false }
end
From Customer View
pdf.text "Hello World"
pdf.text "Customer is #{#customer.name}"
This works fine, producing a PDF file in response to /customers/1.pdf, as expected with a PDF file being generated.
One of the other requirements is to render the pdf to a file and store a copy on the server. Prawn provides the method:
pdf.render_file {path_tofile}
So now if I include this in the View code I can of course save the file on the server. But I'd like to manage this in the controller, as it's related to logic, not view per se.
The first attempt was :
def show
#customer = Customer.find(params[:id])
#pdf = Prawn::Document.new()
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #customer }
format.pdf { render :layout => false }
pdf.render_file {path_to_file}
end
From Customer View
pdf.text "Hello World"
pdf.text "Customer is #{#customer.name}"
PROBLEM
The problem with this attempt is that the PDF is not rendered. I suspected the Controller instance variable is clashing with the Prawnto Plugin pdf variable. But even changing the PDF variable didn't work.
Any suggestions ?
This is how I use prawn in my rails app: http://yob.id.au/2009/05/30/prawn-and-x-accel-redirect.html - it doesn't use prawnto at all.
You can ignore the X-Accel-Redirect stuff unless you use nginx.
Alternatively, another one of the prawn core devs has put together this guide: http://wiki.github.com/sandal/prawn/using-prawn-in-rails