30: Pretty Page Title 

(view original Railscast)

Other translations: It

Nearly all Rails applications use layouts and, because of this, there’s a tendency for each page of an application to have the same title (by title we mean the bit between the <title> tags in the head section). Giving each page its own title isn’t difficult though, and we’ll show you how to do that in this episode.

A First Try

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    <%= stylesheet_link_tag ’asciicasts’ %>

The first part of the ASCIIcasts layout page.

The code above shows the first few lines of the layout file for the ASCIIcasts site. The title element is hard-coded, so will be the same for each page. Let’s take a look at the template for the home page as we’ll be altering it to give the page its own title.

<h2>Recent Episodes</h2>
<ol class="episodeList">
<% @episodes.each do |episode| %>
  <%= render :partial=>’episode_item’, :locals => {:episode => episode} %>
<% end %>

The view template for the home page.

We showed back in episode 8 how you could use content_for to change the content of a layout from within a template. Let’s try using that technique to alter our page titles. At the top of the template above we’ll put the following line.

<% content_for :title do %>Recent Episodes<% end %>

So that the content of the content_for block is shown in the layout we’ll alter the title element of our layout file.

<title>ASCIIcasts - <%= yield :title %></title>

When we refresh our page we can see that the title has been passed from the template into the layout.

The page showing its own title.

The page’s title has now changed.

Using content_for on each page isn’t the most elegant way to do this, especially as we’ll have to put a content_for block on each page in the site. An alternative way is to set an instance variable in each page and to display its value in the layout file. We’ll replace the content_for line in the template with <% @page_title = "Recent Episodes" %> and update the layout so that it shows the contents of the @page_title variable.

<title>ASCIIcasts - <%= @page_title %></title>

This works too, but there is a better way.

Using a Helper Method

The cleanest solution is to create a method on the application_helper file called title, which takes a parameter containing the text we want to show.

module ApplicationHelper
  def title(page_title)
    content_for(:title) { page_title }

As we’re using content_for again, we’ll have to change the layout back so that we’re using yield to display the title.

<title>ASCIIcasts - <%= yield :title %></title>

We can now set the title by calling the title method on each page.

<% title "Recent Episodes" %>

Setting a Default

We might not want to set a different title for every page on our site so it would be good to have a default value to fall back to. We’ll only have to make one small change to our layout file to do this.

<title>ASCIIcasts - <%= yield (:title) || "video.to_s" %></title>

Now, if the title is not set in a particular page, the default value will be shown instead.

An Extra Trick

There is one more trick we can use to cut out some of the repetition in our application. Each page on our site has an h2 element at the top that contains the same text as the page title. To remove this duplication we could remove it from each of our templates and place it at the top of the layout page instead. The relevant part of our layout is now like this.

<div class="main">
  <h2><%= yield(:title) %></h2>
  <%= yield %>

We can now remove all of the h2 elements from each page as they’re handled by the layout.

Our site now has much more relevant page titles which will give users who find pages from your site in search engine results a better idea what your site is about.

The episode’s title in the browser’s title bar.

The ASCIIcasts site had a static title for all of its pages until this episode was written. I updated the site as I was writing this episode.