Create Twitter Cards and LinkedIn Previews with Rails
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.
Most sites are looking for special meta tags to render their previews. These meta tags are defined in 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 Twitters tags for specific information like the @username. These are the tags we need:
Used by all sites
Additionally used by Twitter
twitter:creator(Twitter @username – e.g. the author of an article)
twitter:site(Twitter @username of the site, product, ...)
First, I think you 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 fill it with
content_for. Here is the layout file:
# app/views/application.html.haml %html %head # ... = yield :og_header = tag(:meta, property: "twitter:site", content: "@exceptiontrap") # ...
The Twitter username of the site 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 be:
# 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
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")
You find yourself inserting the same code in a lot of views, or 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 %html %head # ... 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?
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.