Isnor Creative
Isnor Creative Blog
Ruby, Ruby on Rails, Ember, Elm, Phoenix, Elixir, React, Vue

Aug 30, 2015

Embere.js – Injecting Open Graph Tags For Facebook Sharing

I built a public content-oriented website as an Ember application recently. I used the ember-social gem to incorporate Twitter Tweet buttons and Facebook Share buttons.

This made building the buttons a fairly painless process:

{{facebook-share fb-layout='button' url=model.url}}
{{twitter-share url=model.url text=model.twitterShareText via='person' hashtags='great'}} 

The Tweet button worked great, but the Facebook button was not working as expected – it wasn’t picking up any content. I then realized that Facebook does not allow data to be provided for the Share button, instead it uses curl or something like it to scrape the page.

At this point I looked into options – prerender.io, FastBoot, Phantom.js, etc. but they all seemed a bit complicated at the moment. I’m hoping that I may later be able to implement FastBoot when ready for the world, so I was willing to look at the simplest possible solution.

I remembered that in Luke Melia’s RailsConf Lightning Fast Deployments talk he mentioned one possible advantage of this technique is that data can be injected into the index.html as it is served. Since we’re deploying using ember-cli-deploy with Rails serving the index.html from Redis I wondered if that might solve the problem, and it did:

class SiteController < ApplicationController

  def index
    render text: inject_meta(get_html)
  end

  def get_html
    app = "xxx"   
    redis = Redis.new
    current = redis.get("#{app}:current")
    redis.get(current)
  end
  private :get_html 
  
  def inject_meta(html)
    html.gsub('</head>', "#{get_meta}</head>")
  end
  private :inject_meta

  def get_meta
    base_url = "http://www.example.com"
    # event page
    if request.fullpath =~ /events\/[0-9]*/
      id = request.fullpath.split('events/')[1].to_i
      item = Event.find(id).decorate
      meta = %{<meta property="og:title" content="#{item.title}"/>}
      meta = meta + %{<meta property="og:url" content="#{base_url}/events/#{item.id}"/>}

     # news page
     elsif request.fullpath =~ /news\/[0-9]*/
      id = request.fullpath.split('news/')[1].to_i
      item = NewsItem.find(id).decorate
      meta = %{<meta property="og:title" content=" #{item.title}"/>}
      meta = meta + %{<meta property="og:url" content="#{base_url}/news/#{item.id}"/>}
    end  
    
    meta = meta + og_type + og_description(item) + og_image(item)

  rescue => e
    Rails.logger.info "ERROR: #{e}"
    nil
  end
  private :get_meta 

  def og_type
    %{<meta property="og:type" content="article" />}
  end

  def og_image(item)
    %{<meta property="og:image" content="#{item.image_facebook}" />} if item.image_original.present?
  end

  def og_description(item)
    %{<meta property="og:description" content="#{item.content}" />}
  end
    
end

Facebook now curls the URL, which is handled by Rails. Rails gets the index.html file from Redis, and then injects whatever content we need it to into the index.html using gsub. We use request.fullpath to identify the section and item that Facebook is looking for, and we look that up and get the details we need to build open graph tags: image, title, description, url, etc.

Seems to be working like a charm.

In the process I wondered about Google result, but was happy to discover that Google crawls with javascript so our Ember site has been properly indexed.


I am available for Ember consulting work – get in touch to learn more.

Gordon B. Isnor

Gordon B. Isnor writes about Ruby on Rails, Ember.js, Elm, Elixir, Phoenix, React, Vue and the web.
If you enjoyed this article, you may be interested in the occasional newsletter.

I am now available for project work. I have availability to build greenfield sites and applications, to maintain and update/upgrade existing applications, team augmentation. I offer website/web application assessment packages that can help with SEO/security/performance/accessibility and best practices. Let’s talk

comments powered by Disqus