8.6. Accessing the Request and Response Environment

The last couple of examples do something very interesting: the first alters the HTTP headers for the response that is about to be sent, and the second accesses the HTTP REFERER of the request. This is neat, but Rails offers much more when it comes to accessing request and response information.

The following is a list of special identifiers that you can use from within your controller: action_name, cookies, headers, logger, params, request, and response.

Their names are self-descriptive: action_name is a method that returns the name of the current action; cookies represents the cookies for the request; headers is a hash of HTTP headers for the response; logger is a ActiveSupport::BufferedLogger object that's available throughout the application as discussed before; and params is the parameters hash.

request and response are objects that represent the request being processed and the response that is about to be sent, respectively.

You rarely have to modify the response object directly, because Rails takes care of formulating a proper response on its own. However, in the few circumstances where you need to alter the object before it's sent to the client, you can do so easily by accessing one or more of its attributes. Among these, the two that will most likely be used to alter the response object are body and headers.

request, on the other hand, is slightly more complex, and is used frequently enough to warrant further explanation.

To learn more about these two objects, check the documentation for the abstract classes ActionController::AbstractRequest and ActionController::AbstractResponse.

8.6.1. The request Object

The environment of a request is captured in the read-only attribute env. From within a debugging session for a simple request, I obtained the following output for request.env:

(rdb:5) request.env
{"SERVER_NAME"=>"localhost", "PATH_INFO"=>"/main",
"HTTP_ACCEPT_ENCODING"=>"gzip,deflate,bzip2", "HTTP_USER_AGENT"=>"Moz
illa/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/525.13 (KHTML, like Gecko)
 Chrome/0.2.149.30 Safari/525.13", "S
CRIPT_NAME"=>"/", "SERVER_PROTOCOL"=>"HTTP/1.1", "HTTP_HOST"=
>"localhost:3000",
"HTTP_ACCEPT_LANGUAGE"=>"en-US,en", "REM
OTE_ADDR"=>"127.0.0.1", "SERVER_SOFTWARE"=>"Mongrel 1.1.5",
"REQUEST_PATH"=>"/main", "HTTP_ACCEPT_CHARSET"=>"ISO-8859-1,
*,utf-8", "HTTP_VERSION"=>"HTTP/1.1", "REQUEST_URI"=>"/main",
 "SERVER_PORT"=>"3000", "GATEWAY_INTERFACE"=>"CGI/1.2", "HT
TP_ACCEPT"=>"text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/pl
ain;q=0.8,image/png,*/*;q=0.5", "HTTP
_CONNECTION"=>"Keep-Alive", "REQUEST_METHOD"=>"GET"}

That's a lot of information that can be used to obtain details about the client and the request. For example, request.env["HTTP_USER_AGENT"] retrieves the user agent for the browser that's being used (in this case Google Chrome).

env is the only attribute for request, but many methods are defined by this object.

Purposely, many of these methods are there to facilitate access to the same information that's available in the env hash-like object.

headers returns a hash of HTTP headers:

(rdb:5) request.headers
{"SERVER_NAME"=>"localhost", "HTTP_USER_AGENT"=>"Mozilla/5.0 (Windows; U; Windows
NT 6.0; en-US) AppleWebKit/525.13 (KHT
ML, like Gecko) Chrome/0.2.149.30 Safari/525.13",
"HTTP_ACCEPT_ENCODING"=>"gzip,deflate,bzip2", "PATH_INFO"=>"/main", "H
TTP_ACCEPT_LANGUAGE"=>"en-US,en", "HTTP_HOST"=>"localhost:3000",

"SERVER_PROTOCOL"=>"HTTP/1.1", "SCRIPT_NAME"=>"/", "REQ
UEST_PATH"=>"/main", "SERVER_SOFTWARE"=>"Mongrel 1.1.5",
"REMOTE_ADDR"=>"127.0.0.1", "HTTP_VERSION"=>"HTTP/1.1", "HTTP_A
CCEPT_CHARSET"=>"ISO-8859-1,*,utf-8", "REQUEST_URI"=>"/main",
"SERVER_PORT"=>"3000", "GATEWAY_INTERFACE"=>"CGI/1.2", "HT
TP_ACCEPT"=>"text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/pl
ain;q=0.8,image/png,*/*;q=0.5", "REQU
EST_METHOD"=>"GET", "HTTP_CONNECTION"=>"Keep-Alive"}

Similarly, body, content_type, and content_length return the request's body as an IO stream, the MIME type (for example, Mime::XML), and the length of the body in bytes. accepts and format, respectively, return the accepted MIME types and the format (as a MIME type as well) used in the request. If no format is available, the first of the accepted types will be used (for browsers this is usually Mime::HTML).

When you are using the respond_to method introduced in Chapter 5, there is usually no need to invoke these "low-level" mime methods directly. The logic that needs to be implemented for each format in the request (among the registered ones, known to Rails) will be defined within the block passed to the method respond_to.

host, domain, port, port_string, host_with_port, protocol, request_uri, url, and parameters all work as you'd probably expect them to:

(rdb:5) request.host
"localhost"
(rdb:5) request.domain
"localhost"
(rdb:5) request.port
3000
(rdb:5) request.port_string
":3000"
(rdb:5) request.host_with_port
"localhost:3000"
(rdb:5) request.protocol
"http://"
(rdb:5) request.request_uri
"/main"
(rdb:5) request.url
"http://localhost:3000/main"
(rdb:5) request.parameters
{"action"=>"index", "controller"=>"main"}

remote_ip is used to retrieve the IP address that issued the request. This method returns a string containing a single IP, or more IPs if one or more proxies are involved.

The request object also has the two methods method and request_method. These return the HTTP method used for the request as a symbol:

(rdb:5) request.method
:get
(rdb:5) request.request_method
:get

The difference between the two is that method will return :get when a :head request is issued. The reason for this is that from an application standpoint there is usually no need to distinguish between a :get and a :head request.

There is a series of methods that return Boolean values. These methods follow Ruby's convention of ending with a question mark. Among the most common are get?, post?, put?, delete?, head?, ssl?, xhr?, and xml_http_request?.

The first five, corresponding to their five respective verbs, will return true only if the request was issued using the proper HTTP method. request.post?, for example, will return true for POST requests and false for any other type of request verb.

It is common to see an if request.get? or if request.post? statement within an action. This is usually present whenever an action acts differently based on whether the incoming request was a GET or a POST request. In a RESTful controller, if an action is accessible only by a GET or only by a POST request, there is no need to use these methods to check the verb.

Dangerous GET requests

The golden rule of Web development is that any request that retrieves information should be a GET request, and any request that affects the data stored on the server should use the POST HTTP method.

This rule is constantly violated and it's not rare to see publicly accessible links that issue GET requests and have the ability to delete or modify data on the server side. You should avoid this at all costs. Using buttons to submit forms rather than links is a sufficient countermeasure. Another is to use intermediary pages that confirm the requested action.

In the world of REST, you are not limited to GET and POST. You can (and should) use DELETE to destroy resources, POST to create them, PUT to update them, and GET to retrieve them. So PUT and DELETE can affect the state of the server as well, whereas GET shouldn't, whether or not you are in a RESTful context.

Also keep in mind that at this point in time most browsers don't support PUT and DELETE, so these are emulated through POST requests.


ssl? is used to determine whether this was an SSL request, and finally, xml_http_request? (and its alias xhr?) are used to check if the incoming request is an Ajax request. This is done by verifying that the value "XMLHttpRequest" was assigned to the request's X-Requested-With header.

This method is fundamental to Ajax applications, because a response will typically vary depending on whether or not the request was an Ajax one. Ajax requests will normally require a response that updates only certain elements of the page, whereas a regular HTML request requires rendering the whole page.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.189.178.237