Facebook login in a Ruby on Rails application - ruby-on-rails

I'm developing a Ruby on Rails application using the Facebook flogin button with JavaScript.
My code:*
<fb:login-button perms="email" onlogin="createFbSession();"></fb:login-button>
<div id="fb-root"></div>
<script src="http://connect.facebook.net/en_US/all.js">
</script>
<script>
FB.init({
appId:"xxxxxxx", cookie:true,
status:true, xfbml:true
});
function createFbSession() {
FB.getLoginStatus(function(response) {
if (response.session) {
window.location = "<%= fb_login_path %>";
}
});
}
</script>
When I click on the flogin button, sometimes I receive the following error in the popup window:
An error occurred. Please try again later.
What does it mean?

You could use omniauth which lets you use facebook/twitter/openid etc... in ruby without having to use a js library linked in from facebook.
Railscasts have a great episode on a simple onmiauth setup which is well worth a watch and because omniauth returns similar data for all providers just change twitter to facebook and you should be fine.
Omniauth also allows for multiple providers in the same login system, as some people (myself included) prefer to use twitter so enforced facebook login would put me off.

When using the fb:login-button, for some reason, if you don't create it using the content_tag helper it breaks when rendered as html. In rails seems to work when rendered like this: <%= content_tag("fb:login-button", "Log in", {:scope=>"email"}) %>
Note: I'm using rails 3.1, I haven't tried that solution with previous versions.

Related

Facebook Share and Share on Twitter in Rails

On my landing page I want users to be able to Share on Facebook and Share on Twitter that page with a particular message. I would like to be able to know when they have actually post it on Facebook and/or Twitter (any way to get the callback).
What is the correct way to add a Facebook Share link in Rails? I want to have my own button.
I have taken a look at Koala but I am wondering if it is too much because I just want to be able to Share that landing page. I don't want to provide any kind of authentication or anything more complex. The only tricky part is that I need to know when they have actually shared.
Thanks
You can use external service like sharethis,addthis with some option,
For facebook you can use own way of sharing for this by registering with facebook app
consider following example
<a href="#" onclick='postToFeed("<%= image_url%>","<%= somte text %>"); return false;'>
<%= image_tag("btn_fb.png" , :alt=>"Facebook") %>
</a>
<script type="text/javascript">
FB.init({appId: APP_ID", status: true, cookie: true});
function postToFeed(img,name) {
// calling the API ...
var obj = {
method: 'feed',
// redirect_uri: 'http://localhost:3000',
link: 'http://url/',
picture: img,
name: 'NAME',
caption: 'CAPTION',
description: DESCRIPTION
};
function callback(response) {
document.getElementById('msg').innerHTML = "Post ID: " + response['post_id'];
}
FB.ui(obj, callback);
}
</script>

Facebook Authorization on Rails app: why do we need to do Both server and client side authorization?

In Ryan's Railscast on Facebook authorization, he adds some Facebook SDK javascript at the end to "degrade facebook client side authorization with server side authorization." However, I do not see the use of it. If we already set up the authorization from the server side using omniauth, why do we have to add the client-side authorization again? What difference does it make?
The referenced javascript code is (From the linked Railscast):
jQuery ->
$('body').prepend('<div id="fb-root"></div>')
$.ajax
url: "#{window.location.protocol}//connect.facebook.net/en_US/all.js"
dataType: 'script'
cache: true
window.fbAsyncInit = ->
FB.init(appId: '<%= ENV["FACEBOOK_APP_ID"] %>', cookie: true)
$('#sign_in').click (e) ->
e.preventDefault()
FB.login (response) ->
window.location = '/auth/facebook/callback' if response.authResponse
$('#sign_out').click (e) ->
FB.getLoginStatus (response) ->
FB.logout() if response.authResponse
true
UPDATE:
One of the reasons we need to integrate FB.login authorization with the server-side authorization might be that the Omniauth server-side authorization does NOT work if it's accessed within the Facebook iFrame. If the user accesses the application for the first time, the application must ask for permissions; however, oAuth permission dialog cannot be loaded within the iFrame to prevent clickjacking. Calling FB.login can avoid such problem, because it will show the permission box as a popup(Omniauth popup option will not work).
So now I have a genuine reason to integrate client-side authorization, but the code from Railscasts does not work with my current settings. I've chosen to do it the following way.
Right now, I have the following script in my application.html.erb:
<script>
// Additional JS functions here
window.fbAsyncInit = function() {
FB.init({
appId : <%= ENV['FACEBOOK_KEY'] %>, // App ID
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true // parse XFBML
});
};
// Load the SDK Asynchronously
(function(d){
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) {return;}
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
ref.parentNode.insertBefore(js, ref);
}(document));
</script>
And in my view, I have the following link invoking the Facebook log in action:
<%= link_to 'log in with facebook', '/auth/facebook', id: 'fb_log_in_link' %>
I add the following script to the view page where I have the login link.
function login() {
FB.login(function(response) {
if (response.authResponse) {
window.location = '/auth/facebook/callback'
}
});
}
Also, I need to change the link to call the function instead of directing to /auth/facebook/
<%= link_to_function 'log in with facebook', 'login()' %>
Done! The server-side and client-side authorization are fully integrated. Since I was still confused after watching Ryan's Railscast, I want to add a little bit of explanation for those who might be also confused.
The way this works:
Facebook SDK is initailized when the while the page is loaded.
The user clicks the "log in with Facebook" link.
FB.login function is called by the link, and the user goes through all the permissions process (e.g. permission dialog showing up asking for the user's permissions).
Then, the user is directed to /auth/facebook/callback. From routes.rb we have the line match 'auth/:provider/callback', to: 'sessions#create'. Therefore, now the server will either create a new user or simply create a session if the user has already registered before.
Done! The user is logged in.
Merging server-side and client-side authorization has two major advantages:
1. If the user is logged into the application either inside Facebook(via appcenter) he will be logged into the application outside Facebook as well. Vice versa, if the user logs in outside Facebook, he will be logged in automatically if he accesses it within Facebook after.
2. Logging in with /auth/facebook does not work if the user logs in within Facebook iFrame. To prevent clickjacking Facebook prohibits prompting users to auth permissions dialog within Facebook iFrame. The only way to avoid this is to open the dialog in a separate popup, and logging in with FB.login solves the problem.
the short answer is - you don't.
you can choose between client side login (via javascript SDK) and server side login using omniauth.
the disadventage of server-side login is overloading the server for a call you can do from the client.
the advantage is that usually the token is longer (3 months token and not 1-2 hours like client side).
i suggest combine the two. use the client side for initial login, once you do that have an async call from the server side for extended token (only if you have to).
It just says,
Facebook provides a JavaScript SDK that we can use to authenticate a user on the client-side so that it doesn’t look to them like they’ve left our application then returned.
It means that this is for the client side understanding that when user returned from the application, it doesn't look like that they have indeed left it.

jQuery mobile and Google Analytics - single-page template

I didn't find an answer to my question anywhere and I know nothing about javascript, so I can't figure it out myself.
If I have jQuery mobile website built so that every single page is in separate html file (single page template). May I use standard asynchronous Google Analytics code with it, or do I have to make modifications similar to those used in multi page template?
Would be very thankful if someone could answer this question.
Yes, you can use the standard Google Analytics code. You will however, need to "push" certain page views to Google Analytics because of the way jQuery Mobile handles page navigation.
For example, if you have a Contact form on your site at contact.html that, once submitted, goes to a process.php page, and then after completing, the user arrives at thank-you.html, you will need to call some JavaScript to "push" the pageview to Google Analytics.
For example, if your jQuery Mobile page element (data-role="page") has id="thank-you", then I'd use this:
<script type="text/javascript">
$(document).delegate('#thank-you', 'pageshow', function () {
//Your code for each thank you page load here
_gaq.push(['_setAccount', 'UA-XXXXXXX-X']);
_gaq.push(['_trackPageview', '/thank-you.html']);
});
</script>
UPDATE:
I would put this in your script.js file which is included in the head after you load jQuery and jQuery Mobile. This fires on each data-role="page" pageshow event, and is currently working on my live projects just fine.
$('[data-role=page]').live('pageshow', function (event, ui) {
try {
_gaq.push(['_setAccount', 'UA-XXXXXXX-X']);
hash = location.hash;
if (hash) {
_gaq.push(['_trackPageview', hash.substr(1)]);
} else {
_gaq.push(['_trackPageview']);
}
} catch(err) {
}
});

When twitter goes down, elements on my site breaks as well. How to prevent this?

As we know Twitter.com was down in yesterday(2012/07/26) some period of time. In that time my website home page somewhat unresponsive. The homepage was trying to load the twitter feed and failing, and thus other page elements in my site appears broken, like a jquery slider has trouble loading correctly, because its trying to load the twitter API.
Hove to fix this to homepage ignore twitter feed if the site notices that it is down, and displaying a short error notice in place of the feed?
I am using following customize twitter widget (got from here) to show latest 2 twitts in Home page.
<div id='twitter_div'>
<ul id='twitter_update_list'>
</ul>
</div>
<script type='text/javascript' src='http://twitter.com/javascripts/blogger.js'></script>
<script type='text/javascript'>
// to filter #replies in twitter feed
function filterCallback( twitter_json )
{ var result = [];for(var index in twitter_json)
{ if(twitter_json[index].in_reply_to_user_id == null) {result[result.length] = twitter_json[index]; }
if( result.length==2 ) break;}twitterCallback2(result); }
</script>
<script type='text/javascript' src='http://twitter.com/statuses/user_timeline/DUOBoots.json?callback=filterCallback&count=10'></script>
You should delay load your twitter feed. The rest of your page will load right away and if/when twitter goes down it won't block the rest of your page. It's good practice to do this anyway.
See https://dev.twitter.com/discussions/3369 for a discussion with some examples on using jquery to do this.

Error "Origin null is not allowed by Access-Control-Allow-Origin" in jsOAuth

I'm trying to use the twitter API with library jsOAuth.
Full html
<div id="message">Loading..</div>
<script src="jsOAuth-1.3.3.min.js" type="text/javascript"></script>
<script src="http://code.jquery.com/jquery-1.7.min.js" type="text/javascript"></script>
<script type="text/javascript">
var oauth = OAuth({
consumerKey: "-MY-KEY-",
consumerSecret: "MY-SECRET"
});
Updated
oauth.get("http://api.twitter.com/1/statuses/home_timeline.json?callback=?", success, failure);
function success(data){
$("#message").html("Sucess: " + data.text);
var timeline = jQuery.parseJSON(data.text);
console.log(timeline);
$.each(timeline, function (element){
console.log(element.text);
});
}
function failure(data) {
console.log("Throw rotten fruit, something failed");
$("#message").html("Error" );
}
</script>
Result
Full image
Questions
What am I doing wrong?
How can I use the twitter API in my PC.
If you can send me I would appreciate any examples.
Thank you all.
What am I doing wrong?
You are trying to make an AJAX request to Twitter. You are violating cross domain access policies - you cannot access data on the Twitter domain.
How can I use the Twitter API on my PC?
Pick one :
Use JSONP
Use a server-side proxy
Store your code on a file:// path, which removes the cross domain restrictions
Change your browser's security settings to allow this kind of access.
I have styled the unlikely ones in italic.
Also, as an experienced Twitter developer, I have one important note to make about your code: you're using Javascript to access the API. While using JS to do that isn't disallowed, using OAuth in javascript is very unsafe and your application will be blocked from the Twitter API if you used this code on a website.

Resources