Managing SEO-friendly HTML Titles with Rails

I’ve seen this come up a few times in the #rubyonrails IRC channel and figured that I’d post a quick entry for future reference.

Problem: HTML titles

You want to have a clean way to manage the titles on your HTML pages.

```ruby
<html>
    <head>
      <title>Robby on Rails &mdash; Article Title Goes Here</title>
    </head>
    <body>
      ...
Possible Solution(s):

Since the `<title>` tag is usually declared in your layout, you need to
be able to dynamically update this information from almost every action
in your application.

Here are a few ways that I've seen this handled.

1.  Use a instance variable, which would have a default value and you
```text
could override it in any controller action
```ruby
2.  Use the `content_for` method to manage it.

Let's take a few minutes to look at these two approaches.

### Instance Variable

With the instance variable, you might end up with something like:
```erb
```ruby
# app/views/layouts/application.html.erb
  <title>Robby on Rails &mdash; <%= @html_title || 'Default text here...' -%></title>
Then in a controller action...
````ruby
```ruby
# app/controllers/articles_controller.rb
  def show
    # ...
    @html_title = @article.title
  end
So, that's one way to handle it and is probably a more common way.

### The `content_for` helper method approach

This solution is very similar (and underneath uses an instance
variable).

We'll use the
[content_for](http://api.rubyonrails.org/classes/ActionView/Helpers/CaptureHelper.html#M001069)
and a little `yield` action.
```erb
```ruby
# app/views/layouts/application.html.erb
  <title>Robby on Rails <%= (html_title = yield :html_title) ? html_title : '&mdash; Default text here...' %></title>
Then we'll create a helper method.
````ruby
```ruby
# app/helpers/application_helper.rb
  def set_html_title(str="")
    unless str.blank?
      content_for :html_title do
       "&mdash; #{str} "
      end
    end
  end
Now, instead of defining the HTML `<title>` value in the controllers,
we'll just toss this into our html.erb files as necessary.
```erb
```text
<% set_html_title(@article.name) -%>
  ... rest of view

```

..and that’s pretty much it.

Which is the better solution?

This is where we’ll not find a lot of consensus amongst people. I’m a fan of the content_for-based approach and defining the title in views rather than in controller actions. I’m an advocate of skinny controllers and while I’m not a big fan of messy views, I believe that there is less overhead in managing this within the View-world.

I’d love to hear your thoughts on this. Perhaps you have a more eloquent for managing things like this? Do share. :-)

Hi, I'm Robby.

Robby Russell

I run Planet Argon, where we help organizations keep their Ruby on Rails apps maintainable—so they don't have to start over. I created Oh My Zsh to make developers more efficient and host the Maintainable.fm podcast to explore what it takes to build software that lasts.