Sharing on social network
What is the best way for the visitors of my page (not logged in) to share models data (for example articles and courses) on Facebook and Twitter.
I have been looking for an answer without really finding a good implementation.
There are some gems:
- https://github.com/hermango/shareable
- https://github.com/huacnlee/social-share-button But they don't really provide a way to customize either the buttons or the content that needs to be shared.
1 - Should I implement a basic Javascript library
2 - Strip down these gems and build a custom solution based on those
3 - Simply use sharer url like https://www.facebook.com/sharer/sharer.php?
4 - Use Twitter and Koala gem
Also if I want to include sharing buttons for multiple models (for example articles and courses) on the same page how can I dynamically change my open graph and twitter card so that it reflect the correct model data:
<% content_for :head do %>
<!-- Open Graph tags -->
<meta property="og:title" content="<%= @article.title %>" />
<meta property="og:type" content="article" />
<meta property="og:url" content="<%= article_url(@article) %>" />
<meta property="og:description" content="<%= @article.body %>" />
<meta property="og:image" content="<%= absolute_image_url(img.attachment.url) %>" />
<meta property="fb:app_id" content="12345678" />
<!-- Twitter card property -->
<meta name="twitter:card" content="<%= @article.title %>">
<meta name="twitter:site" content="@mytwitter">
<% end %>
Thanks for reading
I've been pretty happy using #3 because it doesn't slow down the page load at all, and you can still customize those pretty well. The downside is you can't include the count of shares because that requires JS.
If you do need those extras from the JS, you could use a service to simplify, or a relatively easy way is just to include the JS libraries using the official instructions. I've found that using services like AddThis are really just a pain to use. Same thing goes for gems, it's just adding an unnecessary layer of abstraction to it that you don't really need.
I just updated my open graph tags tonight and did the following in the head in the layout.
<meta name="twitter:card" content="summary" />
<meta name="twitter:site" content="@gorails" />
<meta name="twitter:title" content="<%= yield :title %>" />
<meta name="twitter:description" content="<%= yield :meta_description %>" />
<meta name="twitter:image" content="<%= asset_url "open-graph.jpg" %>" />
<meta name="twitter:creator" content="@excid3" />
That way the views can have the following code to put in the yield sections.
<%= content_for :title, @episode.name %>
You can then wrap the head code with the following to include it or not based upon existence of the content:
<% if content_for?(:title) %>
<% end %>
Hey Chris, I have been using option #3 and the <% content/yield %> method you suggested but I suspect that Turbolinks is acting up. The share buttons for Facebook and Twitter are working perfectly
<li class="btn-social"><a class="js-social-share facebook" href="https://www.facebook.com/sharer/sharer.php?u=<%= yield :url %>" target="_blank"><i class="fa fa-facebook-official" aria-hidden="true"></i></a>
<li class="btn-social"><a class="js-social-share twitter" href="https://twitter.com/intent/tweet?text=“<%= yield :title %>”&url=<%= yield :url %>&via=twitter" target="_blank"><i class="fa fa-twitter" aria-hidden="true"></i></a>
However if I inspect the markup the meta tags aren't actually up to date unless I manually refresh the page. In other words Turbolinks doesn't allow the content/yield to take place.
Here are my meta tags as you suggested:
<!-- Twitter cards -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@me">
<% if content_for?(:title) %>
<meta name="twitter:title" content="<%= yield :title %>">
<% else %>
<meta name="twitter:title" content="Something else">
<% end %>
I was wondering how you might have solved that yourself.
Okay, so here's why I never noticed it on GoRails. The head tag does get set once and then never gets updated. The next episode you click on gets the link to change on the page, but meta tags stay the same.
Since those links are on the page, you will be fine because that's what's going to initiate the share button and it will take all the properties you set. Anytime Facebook requests the page to get OpenGraph tags, they won't be using Turbolinks so that yield will work properly as well.
Effectively it's a bug, but at the same time it doesn't affect anything (at least for me). Does it cause any issues for you that the meta tags don't get updated?
Yes it's working partially.
I didn't realized it either until I used AddThis widget to expand the scope of possibilities to share. For example AddThis allow to share on whatsapp which is pretty nice with mobile use.
Implementing AddThis with this workaround worked fine with Turbolinks until I noticed a discrepancy between my share button and the one AddThis provide.
So in this case I am not sure what I can do, and I wouldn't deactivate Turbolinks completely as it really provides this single page app fluidity.
That would definitely showcase it.
Well, one solution would be to write some JS that fires on turbolinks page change to update those meta tags. It isn't the most elegant, but it would work just fine I think. See any reasons why that might not work?
Well I don't see any reason it shouldn't work.
I could use this workaround as it's fired on ready page:change
but I don't really see how to update the meta tags from my content/yield...
You would actually need to store the title and url in a data attribute somewhere. Maybe on the twitter and facebook links themselves and then your JS could look for those, then find the attribute, and then populate the meta tag. That's probably what I'd do.
I will try and do that.
It will be an interesting challenge.
And I'll be back with the answer whenever I manage to get it working.
Thanks Chris, good job for keeping up with the questions.
Thanks man! And please do. I'm definitely wanting to correct that on here as well, but it'll probably be a low priority for a while unfortunately. Really hope it works for you so I can do the same sort of thing here.
Chris just a quick one.
I also use <% yield %>
to dynamically change the <title>
meta tag and it works perfectly.
Would you know why <meta>
tag doesn't work and <title>
works?
It should work the same way...
That's interesting. I wonder if there's special stuff in Turbolinks for that because they know the title of the page will always change, therefore they should update the title?
There is an interesting thread in stackoverflow about this "issue":
http://stackoverflow.com/questions/19463978/rails-4-and-turbolinks-meta-tags-not-changing
This "issue" has been raised and shot down a couple times, each time being declared a non-issue by DHH himself, so I wouldn't count on this behavior changing any time soon.
In my case as I needed a quick fix I traded
<!-- content for Open Graph and twitter Cards -->
<% content_for :title, @article.title %>
<% content_for :description, @article.description %>
<% content_for :url, article_url(@article) %>
<% content_for :image, @article.image.url(:medium) %>
for
<script type="text/javascript">
$(document).on('ready page:change', function() {
$("meta[name='twitter\\:title']").attr("content", "<%= @article.title %>");
$("meta[name='twitter\\:description']").attr("content", "<%= @article.description %>");
$("meta[name='twitter\\:image']").attr("content", "<%= @article.image.url(:medium) %>");
$("meta[property='og\\:title']").attr("content", "<%= @article.title %>");
$("meta[property='og\\:description']").attr("content", "<%= @article.description %>");
$("meta[property='og\\:url']").attr("content", "<%= article_url(@article) %>");
$("meta[property='og\\:image']").attr("content", "<%= @article.image.url(:medium) %>");
});
</script>
So far it seems to be working fine.
FWIW -- Here's the slightly more generalized version of the code that I'm using:
<%= javascript_tag do %>
// update the meta tags, since turbolinks will NOT update them
$(document).on('ready page:change', function () {
$("meta[property='og\\:title']").attr("content", "<%= yield_or_default(:og_title, t('meta.og.title')) %>");
$("meta[property='og\\:description']").attr("content", "<%= yield_or_default(:og_description, t('meta.description')) %>");
$("meta[property='og\\:url']").attr("content", "<%= yield_or_default(:og_url, ENV['SITE_HOME_URL']) %>");
$("meta[property='og\\:image']").attr("content", encodeURIComponent("<%= yield_or_default(:og_image, social_meta_app_image) %>") );
$("meta[property='og\\:text']").attr("content", "<%= yield_or_default(:og_text, t('meta.description')) %>");
});
<% end %>
I have a helper method social_meta_app_image
to return the url for a 'devaault' image , and the very common helper method yield_or_default(...)
that is the standard "if there's no content_for:...
then use this default value.
(I'm not sure that I really need the encodeURIComponent
call.)
This lets me change the values with each view by just defining a content_for: ...
or provide
for the values.