Create AMP Accelerated Mobile Pages with Rails

Snippet Ruby on Rails Google AMP

Last updated Apr 25, 2016

Have you noticed the Accelerated Mobile Pages AMP symbol showing up with results in your mobile Google searches yet?

example of amp results in google - prince death 2016

The time has come to upgrade your Rails app for better visibility in mobile search results. An accelerated mobile page (AMP) is simply a HTML document with a very precise structure and NO JavaScript. The only JS allowed on an AMP page is the boilerplate library, which is designed to make traditional web content faster and behave more like a native mobile app. It is critical to follow the latest AMP conventions when designing your page, because your markup must pass all AMP validations to get picked up by search engines.

In this lesson, the code examples will use a Post resource in Rails - about as basic as it can get. 

Resources

Lesson Checkpoints

1. Start with a Route

Let’s start by creating an AMP route - it will come in handy in the next step. Add a custom member route on top of the default rails RESTful routes like so:

resources :posts do
  member do
     get  'amp'
  end
end

This gives us a URL that looks like example.com/posts/:id/amp.

2. Create a Reusable AMP Layout

The regular old layouts/application.html.erb is not going to work for AMP pages. We need to build a new one that strips out all JavaScript and replaces it with the necessary boilerplate code. This layout is reusable, so you can add it to other models as needed. Let’s call it our mobile layout:

layouts/mobile.html.erb

<!doctype html>
<html ⚡>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">

    <%= yield :head %>

    <script async custom-element="amp-carousel" src="https://cdn.ampproject.org/v0/amp-carousel-0.1.js"></script>
    <style amp-boilerplate>...style omitted get latest code from ampproject.org..</style></noscript>
    <script async src="https://cdn.ampproject.org/v0.js"></script>
  </head>
  <body>
    <%= yield %>
  </body>
</html>

Did you notice the <%= yield :head %> line in the previous step? We need to render dynamic content both into the head and body of the document. This helper will make it easy to separate content in the view.

Tip: Let me stress the fact that the Amp Project is in the fast-moving stages of development. The HTML structure and boilerplate code is likely to change. Make sure to grab the latest valid markup before using it in a production app.

3. Create an AMP View

Now we need to add some dynamic content to both the <head> and <body> of each post’s AMP view. This is straightforward, you just need to follow the structure requirements carefully.

We can use the content_for method to pass data that will be rendered into the head of the HTML document.

posts/amp.html.erb

<% content_for :head do %>
    <!-- head content -->
<% end %>

<!-- body content -->

The first step is to reference the original or canonical view in the head of the AMP ⚡ view.

The second step is to add details about our post in JSON format that correspond to Schema.org conventions. This is done inside a special script tag that is allowed to bypass AMP validations.

Head Content

<link rel="canonical" href="<%= post_path(@post) %>">

<script type="application/ld+json">
{
  "@context": "http://schema.org",
  "@type": "Article",
  "headline": "<%= @post.title %>",
  "image": [
    "<%= @post.image_url %>"
  ],
  "datePublished": "<%= @post.updated_at %>"
}

Body Content

<div itemscope itemtype="http://schema.org/Article">
<h1 itemprop="headline"><%= @post.title %></h1>
<p itemprop="articleBody"><%= @post.body %></p>
<amp-img src="<%= @post.image_url %>" width=300 height=300></amp-img>
</div>

According to Google, it is a good idea to have your content structured with Schema.org tags. I would recommend doing this on both the AMP view and the regular view for optimum machine readability. Also, Google provides a structured data testing tool that will ensure your markup is valid.

Images, Video, Etc.

If your view uses images. You will need to replace <img> tags with <amp-img></amp-img> tags. These tags are known as AMP components are they are necessary if your content includes images or video. When the AMP JavaScript is run, it will decide whether or not to load the image based on the likelihood of the user seeing it. This topic is covered in much greater detail in the documentation.

4. Add a Controller Action

The amp action in the controller should behave exactly like the show action, just rendering the mobile layout.

posts_controller.rb

def amp
    @post = Post.find(params[:id])
    render layout: 'mobile'
end

The view is ready to roll. Navigate to localhost:3000/your-post/amp and you should see the bare bones AMP page.

Tip: If you have any features or gems that append JavaScript to the head of your HTML, you will need to disable them on the amp action. AMP will raise a validation error if extra <script> tags are present. In my case, I had to opt out of New Relic monitoring.

5. Help Search Engines Discover your AMP View

Now that we have a working AMP view, we need to tell search engines how to discover it. We do this by adding a link reference within the head of the the regular show view.

posts/show.html.erb

<% content_for :head do %>
    <link rel="amphtml" href="<%= amp_post_path(@post) %>">
<% end %>

6. Validate your AMP Markup

Navigate to http://localhost:3000/posts/1/amp#development=1 or whatever AMP url followed by #development=1.

Then open developer console on your browser and see if you’re getting an validation errors. Command+Option+j in Chrome.

AMP does a nice job of giving you a descriptive alert for each error: 

Once you’ve cleared all validations, you should get a message like this:

Sweet! That about covers the basics. Check out the AMP docs for further information on customizing styles, fonts, JavaScript, etc.

Comments