This is a Nuts & Bolts Article – Tips & Tricks for Developers

Create Twitter Cards and LinkedIn Previews with Rails

by Torsten Bühl

You want a nice preview when your content is shared on Twitter, LinkedIn, and other sites? That's a good idea – it looks better and people are more attracted to click. Let's build a simple solution.

In General

Most sites are looking for special meta tags to render their previews. These meta tags are defined by the Open Graph protocol. Additionally, Twitter introduced its own set for their Twitter Card previews.

But Twitter uses Open Graph tags as a fallback. Hence we use them and just add Twitter's tags for specific information like the username. These are the tags we need:

Used by all sites

  • og:title (corresponds to twitter:title)
  • og:description (corresponds to twitter:description)
  • og:image (corresponds to twitter:image)

Additionally used by Twitter

  • twitter:card (i.e. summary, summary_large_image, photo, ...)
  • twitter:creator (Twitter @username – e.g. the author of an article)
  • twitter:site (Twitter @username of the site, product, ...)

The Implementation

First, you probably don't need these previews for each page. It only makes sense for pages that will be shared – e.g. your home page and articles.

We want a simple and flexible solution. So we define a placeholder with yield in our layout file, and let the view template populate it with content_for. Here is the layout file:

# app/views/application.html.haml
    # ...
    = yield :og_header
    = tag(:meta, property: "twitter:site", content: "@exceptiontrap")
    # ...

The Twitter username is the same for all pages. That's why we put it directly in the layout file.

In our views, we define the meta tags within a content_for block. The home page view could look like:

# app/views/home/index.html.haml
- content_for :og_header
  = tag(:meta, property: "og:title", content: "The Title")
  = tag(:meta, property: "og:description", content: "The Description")
  = tag(:meta, property: "og:image", content: asset_url("summary-large-card-tweet.png"))
  = tag(:meta, property: "twitter:card", content: "summary_large_image")

We use the asset_url helper to specify the image – this gets us the absolute URL and uses the asset pipeline. The image would be stored in app/assets/summary-large-card-tweet.png.

Here is an example of what the article page view could look like:

# app/views/blog/articles/show.html.haml
- content_for :og_header do
  = tag("meta", property: "og:title", content: @article.title)
  = tag("meta", property: "og:description", content: strip_tags(@article.excerpt))
  = tag("meta", property: "og:image", content: asset_url("logos/logo-square-250x250.png"))
  = tag("meta", property: "twitter:card", content: "summary")
  = tag("meta", property: "twitter:creator", content: "@tbuehl")

Do you find yourself inserting the same code in a lot of views, or do you just want a default for all pages? A "default setting" in your layout could be one way to solve this. For example:

# app/views/layouts/application.html.haml
    # ...
    if content_for?(:og_header)
      = yield :og_header
    - else
      = render "layouts/default_og_header"
    # ...
# app/views/layouts/_default_og_header.html.haml
= tag(:meta, property: "og:title", content: "The Title")
= tag(:meta, property: "og:description", content: "The Description")
# ...

Note: The first time you use Twitter Cards, you need to activate them with the Card Validator. Which doesn't make much sense to me, but that's how it works.

How does it look like?

Twitter Screenshot

Let me know

Did this work for you, or do you use another approach? Just ping me at @tbuehl

This is a Nuts & Bolts Series post – join the mailing list below to get more tips & tricks.

← Back to Overview

Try our simple and powerful
application error tracking