Sending Requests And Responses

Defining A Route

The "entrance" of a Rails app is a "route", which tells the Rails app where to find the code to handle the incoming requests. To prove our need for a route, let's try to hit our path first. Visit http://localhost:3000/hello_world and see what happens.

Routing Error
No route matches [GET] "/hello_world"

We haven't defined any route yet, hence the error. We can fix this by defining a route that points these kinds of requests to our new action. To do this, we need three bits of information:

The Rails route file contains a list of routes for the app. Each route is a combination of a HTTP verb (GET, POST etc) and a URL pattern, mapping to a combination of a controller and an action.

The error told us we don't have a route for the combination of a GET request with URL pattern /hello_world.

Let's define a route then, in the routes.rb file in the config directory.

config/routes.rb

Rails.application.routes.draw do
  get '/hello_world' => 'application#hello_world'
end

Inside the block in our routes.rb, we can use methods named after each of the HTTP verbs, e.g. get, post. We then define the URL pattern, then the combination of the controller and the action where the handling code for this type of requests lives.

In our case, we are defining that the code to process this request lives in the ApplicationController's hello_world action. We haven't defined them yet, and we'll do that next.

Now, if you refresh the page http://localhost:3000/hello_world, you will get the following error:

Unknown action
The action 'hello_world' could not be found for ApplicationController

We'll tackle this issue in the next section by defining an action for this route in our ApplicationController.

Ruby Tips

This line that we have in the route file may not look familiar:

get '/hello_world' => 'application#hello_world'

But it is essentially just a method call. It calls the get method passing in a hash as a parameter.

get({'/hello_world' => 'application#hello_world'})

If a hash is the last argument in a method call, Ruby allows you to drop the braces to make the line read better.

Defining An Action

Now it's time to define the hello_world action in the ApplicationController, as our first route specified:

app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  def hello_world
    render plain: 'Hello, World!'
  end
end

The purpose of a controller action is to respond to an HTTP request and build an appropriate HTTP response. For this action, we're completely unconcerned with the details of the request, and simply build our Hello, World! message no matter what. Here we see that accomplished with a call to render, which is used to set the HTTP response. In the call to render above, we've passed in plain: 'Hello, World!', so the generated response will have a content type of text/plain and a body of Hello, World!. Here is what the response will look like:

Cache-Control:max-age=0, private, must-revalidate
Connection:Keep-Alive
Date:Tue, 23 Feb 2016 01:21:23 GMT
Etag:W/"65a8e27d8879283831b664bd8b7f0ad4"
Server:WEBrick/1.3.1 (Ruby/2.3.0/2015-12-25)
X-Content-Type-Options:nosniff
X-Frame-Options:SAMEORIGIN
X-Request-Id:24c23eec-8a37-49d9-bcaf-4f5b3f18aaaa
X-Runtime:0.021203
X-Xss-Protection:1; mode=block

Hello, World!

We can even look at our response from within Rails, let's drop a debugger and inspect the response.

render plain: 'Hello, World!'
binding.pry

### in Pry's console ###
response.body         # => "Hello, World!"
response.content_type # => "text/plain"
response.status       # => 200

We'll see varied uses of render in a bit, but for now, it's enough to recognize that render's job is to accomplish one of the core responsibilities of a controller action: building the HTTP response.

Additionally, notice that our ApplicationController class above inherits from ActionController::Base. The render method (and much more) is made available to us thanks to this inheritance.

Ruby Tips

It's also worth noting that the plain: 'Hello, World!' above is simply a hash argument being passed into render:

render({:plain => 'Hello, World!'})

or,

render({plain: 'Hello, World!'})

Passing hashes this way (especially hashes with symbol keys) is incredibly common in Rails, but it's important to notice that there's no magic here, just standard Ruby syntax.