Ruby

Integrating a rails blog with Facebook instant articles

Publishing blog articles to Facebook

On a recent project, a client asked for a dynamic website and a blog. Since most of their interaction with customers happened through their Facebook Page, they asked for a number of integrations between their new site and Facebook. Aside from the usual like, share, and comment stuff, it was an opportunity to play with the new Instant Article format.

After reading Facebook's documentation, it seemed the simplest way was to create a good old RSS feed and hand it to the Facebook Page. Here is the corresponding article from their documentation.

In this post I will focus only on creating that feed from an existing blog. If you're interested, this minimal example is on GitHub.

Essentially the steps were:

The models

Before diving in, this example will use an Article and an Author model with the following attributes:

Article

Author

The controller

# app/controllers/instant_articles
class InstantArticlesController < ApplicationController
  def index
    @articles = Article.all
  end

  def show
    article = Article.find(params[:id])
    render layout: false, locals: { article: article }
  end
end

Pretty conventional, except for the show action. We need to pass the article as a local variable to the render method instead of using an instance variable. The reason for that will be clear in the index.rss.builder template where we will need to render the show template again.

The show template

This is based on a sample code from Facebook docs. You can find it here.

<!-- app/views/show.html.erb -->`
<!doctype html>
<html lang="en" prefix="op: http://media.facebook.com/op#">
  <head>
    <title>My Blog | <%= article.title %></title>
    <meta charset="utf-8">
    <link rel="canonical" href="<%= article_url(article.id) %>">
    <meta property="op:markup_version" content="v1.0">
  </head>
  <body>
    <article>
      <header>
        <h1><%= article.title %></h1>
        <h2><%= article.subtitle %></h2>
        <time class="op-published" datetime="<%= article.created_at.iso8601 %>">
          <%= article.created_at %>
        </time>
        <address>
          <%= link_to article.author.name, article.author %>
        </address>
        <figure>
          <img src="<%= article.cover_url %>" alt="<%= article.cover_description %>">
          <figcaption><%= article.cover_description %></figcaption>
        </figure>
        <h3 class="op-kicker"><%= article.kicker %></h3>
      </header>
      <%= article.body.html_safe %>
      <footer>
        <aside>
          <p><%= article.author.name %></p>
          <%= article.author.bio.html_safe %>
        </aside>
      </footer>
    </article>
  </body>
</html>

A few things to note here. First, make sure there is a link to the original content in the <head>. Second, Facebook expects <time> to have its datetime attribute in a specific format (ISO 8601).

Again, to make things simple here, I used the created_at time stamp for the date, but you'll probably want to create a published_at attribute instead, and add another time stamp for updated_at, so that Facebook knows when an article is modified.

Now let's wrap this all together and create our RSS feed.

The index template

This is what we want. The goal is to create the same XML structure as this.

# app/views/index.rss.builder
xml.rss version: '2.0', 'xmlns:content' => 'http://purl.org/rss/1.0/modules/content' do
  xml.channel do
    xml.title 'My Blog'
    xml.link articles_url
    xml.description 'Instant Articles from my blog.'
    xml.language 'en-us'

    @articles.each do |article|
      xml.item do
        xml.title article.title
        xml.link article_url(article.id)
        xml.content :encoded do
          xml.cdata! render(template: 'instant_articles/show', locals: { article: article }, formats: :html, layout: false)
        end
        xml.guid article_url(article.id)
        xml.pubDate article.created_at.iso8601
        xml.author article.author.name
      end
    end
  end
end

The magic happens at line 13, where we render the show template above.

Watch out for the format of the time stamps, ISO 8601 again.

Takeaway

There are more things you could/should do to complete the integration, such as creating rich media elements, configuring a newsfeed preview, or creating a style. I definitely recommend checking the documentation, it's pretty extensive and it has code samples.

Using the RSS feed to import articles is not optimal if you want immediate feedback on the import process. For that you could use the Instant Articles API. But the RSS feed integrates nicely with the publishing tools, giving you a nice and easy way to edit your Instant Articles on Facebook and scheduling them to be shared on the page.