Managing SEO-friendly HTML Titles with Rails
28 comments Latest by Telecommunications Thu, 20 Aug 2009 08:27:47 GMT
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.
<html>
<head>
<title>Robby on Rails — 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.
- Use a instance variable, which would have a default value and you could override it in any controller action
- Use the
content_formethod 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:
# app/views/layouts/application.html.erb
<title>Robby on Rails — <%= @html_title || 'Default text here...' -%></title>
Then in a controller action…
# 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 and a little yield action.
# app/views/layouts/application.html.erb
<title>Robby on Rails <%= (html_title = yield :html_title) ? html_title : '— Default text here...' %></title>
Then we’ll create a helper method.
# app/helpers/application_helper.rb
def set_html_title(str="")
unless str.blank?
content_for :html_title do
"— #{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.
<% 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. :-)
Enjoying the content? Be sure to subscribe to my RSS feed.






Well the way I do it, is basically set a variable in the application.rb controller and print that out in the layout:
in application.rb:
before_filter :meta_defaults
the application.html.erb looks like thise wise:
... now if I want to have a different title there, I simply overwrite the @meta_title in my controller’s action.
Not sure it is entirely clean/dry etc.. but works perfectly fine for me :)
-J
By the way, just put <% @title = ‘My mega title’ %> inside view, huh?
@Timur: yeah, you could do that too. Although, I’m not a fan of setting instance variables in my views. It feels cleaner (to me)... to call a helper in the view to define it than define a variable value (even if that’s what happening in the background).
Since the action views are generated before the layout you can set the instance var there instead of setting it in the controller.
I’ve never found a great solution to this primarily because I’m not sure what design pattern I’m looking for with my title content anyway. The pattern is clear for blogs or forums but not so clear for more unique apps.
Oh, and one reason to define it in the views rather than controllers is because sometimes (like with an invalid record) the ‘create’ action displays the ‘new’ view. So you want what actually shows up to define the title.
Another reason that I prefer the helper approach is that you can have this be where you define your delimeter. In my example above, I used a mdash.
If you want to have a few levels down you can call the helper a few times.
For example… to produce:
Planet Argon – Services – Rails Consulting
I might do the following:
<% set_html_title('Services') %><% set_html_title('Rails Consulting') %>I suppose the helper could modified you to provide it an array of strings and call it like:
<% set_html_title( 'Services', 'Rails Consulting' ) %>to produce the desired output.
I usually it in at the top of my views with:
<% @title = "Editing #{@document.name}" %>and then in the application layout do something like this:
<title>Governoration.com - <%= gently_escape(@page_title) || "A simple, powerful online management tool for school governing bodies" %></title>where gently_escape makes sure the result is valid xhtml and still pretty, the or means there is always a useful title for seo.
I also do the same with some other meta tags like author, description and keywords with instance variables if the content is available on that page.
<meta name="description" content="<%= gently_escape(@meta_description) || "Governoration is an online communication and resource facility for school Governing Bodies. By providing instant access to policies, minutes, reports and other related documents Governors can make decisions and remain informed" %>" />An old episode (30) of Ryan Bates’ Railscasts discussed this and suggests the content_for helper. I guess the only difference is he wanted to make it so clean that he made the name of the helper method simply
title.<% title 'My Title' %>I’m pretty happy with the plugin headliner>
http://the.railsi.st/2007/5/3/headliner-dry-up-your-page-titles
I’m pretty happy with the plugin headliner>
http://the.railsi.st/2007/5/3/headliner-dry-up-your-page-titles
I would argue that the page title is entirely a view responsibility and as such has no place being set within the controller.
Secondly, the usage of a helper to provide the function of injecting the page title seems overly complex.
In our organization we inject the title via content_for, using the one-line version (since it’s a short string):
<% content_for :title, ‘Hello World’ %>
Simple, with all responsibility for over-riding the title in the individual view page.
Many developers seem shocked to see the one line content_for form, since the block form is much more common.
For SEO purposes I’d much prefer simply “Managed SEO-friendly HTML Titles with Rails” than having a prefix as you’re not giving up density, and really how much use is the site title? So if we throw away the need for prefixes and delimiters you pretty much don’t need a helper either.
The second issue is HTML escaping. You may want to include a html entity in the title, so you can’t simply escape it in the layout, but you need to ensure user generated content is escaped. At the point of the application layout I assume all content is suitably escaped.
So these days I stick with the following convention to begin with:
In the layout I simply force everyone to explicitly set page titles (if only there was a way to enforce the quality of the title too)
My only suggestion, and maybe its stating the obvious, is not to cargo cult someone else’s approach and do whatever makes sense in terms of your immediate needs and your own conventions.
I came up with something that was awfully similar to the RailsCast approach. I even made a helper method called title. This is what I’m going to stick with.
I prefer the content_for way, but for most of projects I use the headliner plugin.
i actually use the instance variable method on most projects, but recently have found that the content_for method is much better – for one simple reason:
when you have a create action and you use the instance variable method you have to set it before doing render :action => ‘new’ if validation of the record fails
I like the Headliner plugin: http://the.railsi.st/2007/5/3/headliner-dry-up-your-page-titles
I like the Headliner plugin: http://the.railsi.st/2007/5/3/headliner-dry-up-your-page-titles
winfield: +1 . Respect the MVC paradigm: the title should be defined in the view
badrobby: I do have the same helper, althought the method name is title instead of set_html_title, then it’s much more seksy combined with haml:
winfield: +1 . Respect the MVC paradigm: the title should be defined in the view
badrobby: I do have the same helper, althought the method name is title instead of set_html_title, then it’s much more seksy combined with haml:
winfield: +1 . Respect the MVC paradigm: the title should be defined in the view
badrobby: I do have the same helper, althought the method name is title instead of set_html_title, then it’s much more seksy combined with haml:
jerome – the title is data. Just because you display it in the view it doesn’t mean you need to define it there.
Titles are often dynamically generated, and views can be quite reasonably shared between controllers. A helper method that returns the title seems to be a flexible approach to me; if you have site wide logic for generating your title you can define it in ApplicationHelper and override the method in other helpers as required. In order to keep things DRY I’ve even set up content_for hooks that can be used to override the title set by the helper, but I only use content_for when I need to make an exception to the rule. Admittedly this complexity comes in more handy when dealing with h1 tags than it does the title tag, as you may want to put HTML tags within your h1 tag.
From an SEO perspective I’m reliably informed that only the first seven words of the title are of any use as the engines tend to ignore the rest. Try and keep the relevant part of your title at the beginning. This also aids usability for people using systems that show the beginning of the title when windows are minimised in the status bar (i.e. they can tell which page is which even when the browser is minimised).
I prefer the content_for way.
There are good reasons to use both ways depending on the app. Titles may simply be a field value (like a post title) or may be much more complex. A view should never have to understand why (Controller) it is rendering something only what (Model) it is rendering and how (View).
As soon as your views start having to understand what prompted the rendering you are out-of-bounds and creating a complex chain of dependencies. For example, you may render the page title in a number of languages depending on a user preference which is fine if there is a user logged in or if there is a translation available in the preferred language. Now the view is having to know a lot more about the workings of your application than it should and those decisions should be handled by the Controller.
I use my Title Helpers plugin.
Just released a first version of the EasyTitles plugin
There is one advantage content_for approach seems to have, you can use it with fragment caching. If you have a forum and you want to generate keywords, title, description based on the actual article/post, you’d most likely want to generate them based on your @article
<% content_for :meta do %> <% cache ‘meta_#{params[:id]}’ do @article = Article.find_by_id(params[:id]) %>
<%= @article.title %> = @article.content.slice(1,126)>”/><% end %> <% end %>
oh well, the code got screwed up.
title : <%= @article.title %> description : <%= @article.content.slice(1,126) %>
@article is fragment cached so this way for pages that don;t really change in time, it’s an opportunity to be good with your db server
Thanks for the knowledge on…....