# Response
From the controller's point of view, there are three ways to create an HTTP response:
Call
render
to create a full response to send back to the browserCall
redirect_to
to send an HTTP redirect status code to the browserCall
head
to create a response consisting solely of HTTP headers to send back to the browserUsing render
In most cases, the
[ActionController::Base#render](https://api.rubyonrails.org/v7.0.4/classes/AbstractController/Rendering.html#method-i-render)
method does the heavy lifting of rendering your application's content for use by a browser. There are a variety of ways to customize the behavior ofrender
. You can render the default view for a Rails template, or a specific template, or a file, or inline code, or nothing at all. You can render text, JSON, or XML. You can specify the content type or HTTP status of the rendered response as well .If you want to see the exact results of a call to
render
without needing to inspect it in a browser, you can callrender_to_string
. This method takes exactly the same options asrender
, but it returns a string instead of sending a response back to the browser.#Action View render "edit" render action: :edit #Rendering an Action's Template from Another Controller render "products/show" render template: "products/show" #with :inline render inline: "<% products.each do |p| %><p><%= p.name %></p><% end %>" #Rendering Text render plain: "OK" #Rendering HTML render html: helpers.tag.strong('Not Found') #rendering json render json: @product #rendering XMl render json: @product #Rendering Vanilla JavaScript render js: "alert('Hello Rails');" #Rendering raw body render body: "raw" #Rendering raw file render file: "#{Rails.root}/public/404.html", layout: false #Rendering objects render MyRenderable.new #The :status Option render status: 500 render status: :forbidden
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39Using redirect_to
Another way to handle returning responses to an HTTP request is with
redirect_to
. As you've seen,render
tells Rails which view (or other asset) to use in constructing a response. Theredirect_to
method does something completely different: it tells the browser to send a new request for a different URL. For example, you could redirect from wherever you are in your code to the index of photos in your application with this call:redirect_to photos_url
1You can use
redirect_back
to return the user to the page they just came from. This location is pulled from theHTTP_REFERER
header which is not guaranteed to be set by the browser, so you must provide thefallback_location
to use in this case.redirect_back(fallback_location: root_path)
1Using Head to build header-only responses
The
head
method can be used to send responses with only headers to the browser.head :bad_request
1Or you can use other HTTP headers to convey other information:
head :created, location: photo_path(@photo)
1
# Other Response Type
Sending File
If you want to send a file that already exists on disk, use the
send_file
method.class ClientsController < ApplicationController # Stream a file that has already been generated and stored on disk. def download_pdf client = Client.find(params[:id]) send_file("#{Rails.root}/files/clients/#{client.id}.pdf", filename: "#{client.name}.pdf", type: "application/pdf") end end
1
2
3
4
5
6
7
8
9This will read and stream the file 4 kB at the time, avoiding loading the entire file into memory at once. You can turn off streaming with the
:stream
option or adjust the block size with the:buffer_size
option.If
:type
is not specified, it will be guessed from the file extension specified in:filename
. If the content-type is not registered for the extension,application/octet-stream
will be used.Sending Data
Sometimes you may want to send a file to the user instead of rendering an HTML page.
To stream data to the client, use
send_data
:require "prawn" class ClientsController < ApplicationController # Generates a PDF document with information on the client and # returns it. The user will get the PDF as a file download. def download_pdf client = Client.find(params[:id]) send_data generate_pdf(client), filename: "#{client.name}.pdf", type: "application/pdf" end private def generate_pdf(client) Prawn::Document.new do text client.name, align: :center text "Address: #{client.address}" text "Email: #{client.email}" end.render end end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20The
download_pdf
action in the example above will call a private method which actually generates the PDF document and returns it as a string. This string will then be streamed to the client as a file download, and a filename will be suggested to the user. Sometimes when streaming files to the user, you may not want them to download the file. Take images, for example, which can be embedded into HTML pages. To tell the browser a file is not meant to be downloaded, you can set the:disposition
option to "inline". The opposite and default value for this option is "attachment".Restful Downloads
While
send_data
works just fine, if you are creating a RESTful application having separate actions for file downloads is usually not necessary. In REST terminology, the PDF file from the example above can be considered just another representation of the client resource. Rails provides an easy and quite sleek way of doing "RESTful downloads". Here's how you can rewrite the example so that the PDF download is a part of theshow
action, without any streaming:class ClientsController < ApplicationController # The user can request to receive this resource as HTML or PDF. def show @client = Client.find(params[:id]) respond_to do |format| format.html format.pdf { render pdf: generate_pdf(@client) } end end end
1
2
3
4
5
6
7
8
9
10
11For this example to work, you have to add the PDF MIME type to Rails. This can be done by adding the following line to the file
config/initializers/mime_types.rb
:Mime::Type.register "application/pdf", :pdf
1Now the user can request to get a PDF version of a client just by adding ".pdf" to the URL:
GET /clients/1.pdf
1Live Stream
Rails allows you to stream more than just files. In fact, you can stream anything you would like in a response object. The
[ActionController::Live](https://api.rubyonrails.org/v7.0.4/classes/ActionController/Live.html)
module allows you to create a persistent connection with a browser. Using this module, you will be able to send arbitrary data to the browser at specific points in time.class MyController < ActionController::Base include ActionController::Live def stream response.headers['Content-Type'] = 'text/event-stream' 100.times { response.stream.write "hello world\n" sleep 1 } ensure response.stream.close end end
1
2
3
4
5
6
7
8
9
10
11
12
13The above code will keep a persistent connection with the browser and send 100 messages of
"hello world\n"
, each one second apart.
← Request ERB Template →