# 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 browser

  • Call redirect_to to send an HTTP redirect status code to the browser

  • Call head to create a response consisting solely of HTTP headers to send back to the browser

  • Using 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 of render. 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 renderwithout needing to inspect it in a browser, you can call render_to_string. This method takes exactly the same options as render, 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
    39
  • Using redirect_to

    Another way to handle returning responses to an HTTP request is with redirect_to. As you've seen, rendertells Rails which view (or other asset) to use in constructing a response. The redirect_tomethod 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
    
    1

    You can use redirect_backto return the user to the page they just came from. This location is pulled from the HTTP_REFERERheader which is not guaranteed to be set by the browser, so you must provide the fallback_locationto use in this case.

    redirect_back(fallback_location: root_path)
    
    1
  • Using Head to build header-only responses

    The head method can be used to send responses with only headers to the browser.

    head :bad_request
    
    1

    Or 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
    9

    This 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
    20

    The 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_dataworks 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 the showaction, 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
    11

    For 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
    
    1

    Now the user can request to get a PDF version of a client just by adding ".pdf" to the URL:

    GET /clients/1.pdf
    
    1
  • Live 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
    13

    The above code will keep a persistent connection with the browser and send 100 messages of "hello world\n", each one second apart.