Processing of Requests
Learn to further process requests after getting a REST request.
In the previous lesson, we worked out how Action Dispatch routes an incoming request to the appropriate code in your application. Now let’s see what happens inside that code.
Action methods
When a controller object processes a request, it looks for a public instance method with the same name as the incoming action. If it finds one, that method is invoked. If it doesn’t find one and the controller implements method_missing()
, that method is called, passing in the action name as the first parameter and an empty argument list as the second. If no method can be called, the controller looks for a template named after the current controller and action. If found, this template is rendered directly. If none of these things happens, an AbstractController::ActionNotFound
error is generated.
Controller environment
The controller sets up the environment for actions (and, by extension, for the views that they invoke). Many of these methods provide direct access to the information contained in the URL or request:
-
action_name
The name of the action currently being processed.
-
cookies
The cookies are associated with the request. Setting values into this object stores cookies on the browser when the response is sent. Rails support for sessions is based on cookies.
-
headers
A hash of HTTP headers will be used in the response. By default,
Cache-Control
is set tono-cache
. We might want to setContent-Type
headers for special-purpose applications. Note that we shouldn’t set cookie values in the header directly. Use the cookie API to do this. -
params
A hash-like object containing request parameters along with pseudo parameters generated during routing. It’s hash-like because we can index entries using either a symbol or a string. The
params[:id]
andparams['id']
return the same value. Idiomatic Rails applications use the symbol form. -
request
The incoming request object. It includes these attributes:
-
The
request_method
attribute returns the request method, one of:delete
,:get
,:head
,:post
, or:put
. -
The
method
attribute returns the same value asrequest_method
except for:head
, which it returns as:get
because these two are functionally equivalent from an application’s point of view. -
The
delete?
,get?
,head?
,post?
, andput?
attribute returntrue
orfalse
based on the request method. -
The
xml_http_request?
andxhr?
attribute returntrue
if this request was issued by one of the Ajax helpers. Note that this parameter is independent of themethod
parameter. -
The
url()
attribute, which returns the full URL used for the request. -
The
protocol()
,host()
,port()
,path()
, andquery_string()
attribute, which return components of the URL used for the request based on the following pattern:protocol://host:port/path?query_string
. -
The
domain()
attribute, which returns the last two components of the domain name of the request. -
The
host_with_port()
attribute, which is ahost:port
string for the request. -
The
port_string()
attribute, which is a:port
string for the request if the port is not the default port (80 for HTTP, 443 for HTTPS). -
The
ssl?()
attribute, which istrue
if this is an SSL request. In other words, the request was made with the HTTPS protocol. -
Tbe
remote_ip()
attribute, which returns the remote IP address as a string. The string may have more than one address in it if the client is behind a proxy. -
The
env()
attribute, which is the environment of the request. We can use this to access values set by the browser, like:request.env['HTTP_ACCEPT_LANGUAGE']
-
The
accepts()
attribute, which is an array withMime::Type
objects that represent the MIME types in the Accept header. -
The
format()
attribute, which is computed based on the value of theAccept
header, withMime[:HTML]
as a fallback. -
The
content_type()
attribute, which is the MIME type for the request. This is useful forput
andpost
requests. -
The
headers()
attribute, which is the complete set of HTTP headers. -
The
body()
attribute, which is the request body as an I/O stream. -
The
content_length()
attribute, which is the number of bytes purported to be in the body.
-
-
response
The response object, filled in during the handling of the request. Normally, this object is managed for us by Rails.
-
session
A hash-like object representing the current session data.
In addition, a logger is available throughout Action Pack.
Responding to the user
Part of the controller’s job is to respond to the user. There are basically four ways of doing this:
- The most common way is to render a template. In terms of the MVC paradigm, the template is the view. It takes the information provided by the controller and uses it to generate a response to the browser.
- The controller can return a string directly to the browser without invoking a view. This is fairly rare but can be used to send error notifications.
- The controller can return nothing to the browser. This is sometimes used when responding to an Ajax request. In all cases, however, the controller returns a set of HTTP headers, because some kind of response is expected.
- The controller can send something other than HTML data to the client. This is typically a download of some kind, such as a PDF document or a file’s contents.
A controller always responds to the user exactly one time per request. This means we should have just one call to a render()
, redirect_to()
, or send_xyz()
method in the processing of any request. A DoubleRenderError
exception is thrown on the second render.
Because the controller must respond exactly once, it checks to see whether a response has been generated just before it finishes handling a request. If not, the controller looks for a template named after the controller and action and automatically renders it. This is the most common way that rendering takes place. You may have noticed that in most of the actions in our shopping cart tutorial we never explicitly rendered anything. Instead, our action methods set up the context for the view and return. The controller notices that no rendering has taken place and automatically invokes the appropriate template.
We can have multiple templates with the same name but with different extensions. For example, .html.erb
, .xml.builder
, and .js.erb
. If we don’t specify an extension in a render request, Rails assumes html.erb
.
Rendering templates
A template is a file that defines the content of a response for our application. Rails supports three template formats out of the box. It uses erb
, which is embedded Ruby code typically with HTML, builder
, a more programmatic way of constructing XML content, and RJS
, which generates JavaScript.
By convention, the template for action
of controller
will be in the file app/views/controller/action.type.xxx
. In this case, type
is the file type, including html
, atom
, or js
, and xxx
is one of erb
, builder
or scss
. The app/views
part of the name is the default. We can override this for an entire application by setting this:
ActionController.prepend_view_path dir_path
The render()
method is the heart of all rendering in Rails. It takes a hash of options that tell it what to render and how to render it.
It’s tempting to write code in our controllers that look like this:
Get hands-on with 1400+ tech skills courses.