With our route properly handling requests to the action /hello_world
, let's change our action to render some HTML instead:
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
def hello_world
render inline: '<em>Hello, World!</em>'
end
end
Here we use inline:
instead of plain:
to pass the response body string to render
, which sets the content type of the response to HTML. Here is what our response will look like:
HTTP/1.1 200 OK
Cache-Control: max-age=0, private, must-revalidate
Connection: Keep-Alive
Content-Length: 22
Content-Type: text/html; charset=utf-8
Date: Tue, 23 Feb 2016 02:44:36 GMT
Etag: W/"1e401bc81108cb3e3dba191111bf9059"
Server: WEBrick/1.3.1 (Ruby/2.3.0/2015-12-25)
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Request-Id: a2eac900-60da-460d-9757-94d8c41c4624
X-Runtime: 0.252767
X-Xss-Protection: 1; mode=block
<em>Hello, World!</em>
Most of the above is very similar to our last HTTP response for the hello world
action. Notice, that there are a few differences, and one of those differences is
that the response body now has em
tags wrapped around it.
Let's inspect our response
object within Rails as well:
# assuming we're inside the hello_world action above...
render inline: '<em>Hello, World!</em>'
binding.pry
### inside Pry ###
response.body # => "<em>Hello, World!</em>"
response.content_type # => "text/html"
response.status # => 200
Here we see the content type set appropriately to text/html
, thanks to using inline:
instead of plain:
. The status code here also defaults to 200
(OK
), which is fine, but if we wanted to change it, we could do so in a render
call simply by passing e.g. status: 404
along as well.
Now if you refresh the page, you'll see our Hello, World!
message displayed in italics in your browser, thanks to the text/html
content type and the <em>
tags in the HTML response body string.
We've got requests being processed by an action now, but there's something amiss: there's content in our action.
The problem here is that a controller's job is not to hold content, it's to… well, control things. A cleanly written controller action won't do much of anything itself, other than orchestrate the calling of other parts of the application and, when needed, put those results together.
A controller action is merely the director of the request handling, it should delegate other responsibilities to other parts of the application. But already, ours is doing something it shouldn't have to: it's holding our content, the HTML message.
To fix this, let's move that HTML out of our action.
HTML content belongs in a View, so let's create one to hold it:
<!-- app/views/application/hello_world.html -->
<html>
<body>
<p>Hello, World!</p>
</body>
</html>
This is the same HTML as before, but now stored in its own view file. And notice where we placed it, because this is important:
app/views/application/hello_world.html
All views live in the app/views
directory. From there, they are placed in a directory that corresponds to the controller and action that uses them. Here, this leaves us with an app/views/application/hello_world.html
file.
With our view defined, let's make use of it in our controller:
### app/controllers/application_controller.rb ###
class ApplicationController < ActionController::Base
def hello_world
render 'application/hello_world'
end
end
NOTE: Make sure to restart your Rails server with bundle exec rails server
before reloading the page
Now, we've used render
a couple times already, but here we're doing something different because we're simply passing it a string. Furthermore, you'll note that this string matches the path of the view that we just created. As a result, our hello_world
action will now render our HTML response body using our freshly defined application/hello_world
view.
Effectively, using render
this way is the equivalent of doing:
render inline: File.read('app/views/application/hello_world.html')
Whether we're pointing it to a view or setting the response body in the action itself, keep in mind that it's always the job of render
to set the HTTP response body. Though, as we pointed out above, it's typically bad practice to leave content sitting in your controller, so quite commonly you'll see render
calls rendering views, like the one above.