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
.
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.
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.
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.