Using Omniauth facebook and ajax - ruby-on-rails

I'm trying to allow a user to sign in via facebook, and not be redirected off of the current page. I'm currently using Rails with omniauth-facebook and devise for authentication. I'm assuming the best way to do this is via ajax once I've received authentication from facebook via the Javascript api. However, I'm not sure what I need to pass to the callback url for omniauth to verify the authentication. Here's what I currently have (I'm trying to avoid using jquery for the time being)
:javascript
window.fbAsyncInit = function() {
// init the FB JS SDK
FB.init({
appId : 'app-id', // App ID from the app dashboard
channelUrl : '//localhost:3000/channel.html', // Channel file for x-domain comms
status : true, // Check Facebook Login status
cookie : true,
xfbml : true // Look for social plugins on the page
});
// Additional initialization code such as adding Event Listeners goes here
document.getElementById('facebook-login').onclick = function(event) {
FB.login(function(response) {
if (response.authResponse) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
console.log(xhr);
if (xhr.readyState == 4) {
console.log(xhr.responseText);
}
}
xhr.open('GET', 'http://localhost:3000/users/auth/facebook/callback', true);
xhr.send(null);
} else {
console.log("Something when horrible wrong");
}
}, {scope: ''});
}
};
// Load the SDK asynchronously
(function(d, s, id){
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {return;}
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/all.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
The thing I'm most unsure about is if I'm calling my own endpoint (users/auth/facebook/callback) correctly, or if I need to pass anything to it. Any help would be greatly appreciated.

For me, the problem was making a GET request instead of a POST request.
Changed to POST and the problem is gone.
I would have left it as a comment, as I'm not leaving further information to justify this solution, but i'm new at this (StackOverflow); I don't have enough points to be able to comment.
Anyway, Hope it helps!

Related

Adding Google Ads Conversion Tracking Code Manually to Facebook Customer Chat

I have setup a Google Ads account and a conversion goal.
In my website I have added a button Facebook customer chat.
I would like to add Google Ads conversion tracking code to the fb chat button so that every time someone starts chatting the system tracks the conversion.
(preferably without using Google Tag Manager)
Here is the chat code so far without the tracking code:
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function() {
FB.init({
xfbml : true,
version : 'v3.3'
});
};
(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = 'https://connect.facebook.net/en_US/sdk/xfbml.customerchat.js';
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>
<!-- Your customer chat code -->
<div class="fb-customerchat"
attribution=setup_tool
page_id="xxxxxxxxxxx"
theme_color="#9B813B"
logged_in_greeting="We are live and ready to chat with you now. Say something to start a live chat."
logged_out_greeting="We are live and ready to chat with you now. Say something to start a live chat."
greeting_dialog_display="show"
greeting_dialog_delay="5">
</div>
And here is the tracking code I got from Google AdWords Conversion on AJAX Form? :
window.google_trackConversion({
google_conversion_id: 'AW-xxxxxxxxx',
google_conversion_language: "en",
google_conversion_format: "3",
google_conversion_color: "ffffff",
google_conversion_label: "xxxxxxxxx",
google_remarketing_only: false,
onload_callback : function() {
console.log("Conversion Sent Contact");
}
});
Thank you!
You could add a onclick function to the chat button to fire the google ads conversion script

Ember-cli & Facebook-share buttons - how to?

Goal - Have share buttons for Facebook
I've had various problems, I've managed to solve most issues but never all at the same time.
ReferenceError: FB is not defined (error in the console)
"FB init function gives wrong version error" (error in the console)
My button does not render after transitioned to another route.
My button renders but there is no spacing around the button to adjacent stuff on the initial route
About that rendering issue (the - / hyphen is there to notice the spacing issue)
Rendering for the 1st time:
Rendering for the 2nd+ time:
What I've learned:
Facebook wants a <div id="fb-root"></div> as the first element inside your <body>
FB.XFBML.parse() can be called after didInsertElement to render a component after a transition
I made a JSBin boilerplate attempt, it's currently stuck at a undefined FB error.
http://emberjs.jsbin.com/fevoyuhiso/2/edit
Partial answer I'm also interested in:
Understanding how complex the solution at least must me to achieve a good result ("it must include an initializer, and a view/component!" or "you can solve this by just having ...")
Parts that may be of use
A post about "after FB.init()"
How to detect when facebook's FB.init is complete
An initializer
/* global FB */
export default {
name: 'facebook',
initialize: function() {
var fbAsyncInit = function() {
FB.init({
appId : 123,
xfbml : true,
version : 'v2.2'
});
};
(function(d, s, id){
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {return;}
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
window.fbAsyncInit = fbAsyncInit;
}
};
A component
/* global FB */
import Ember from 'ember';
export default Ember.Component.extend({
tagName: 'div',
classNames: 'fb-like',
attributeBindings: [
'data-href',
'data-layout',
'data-action',
'data-show-faces',
'data-share'
],
onDidInsertElement: function() {
Ember.run.schedule('afterRender', FB.XFBML.parse);
}.on('didInsertElement'),
init: function() {
Ember.run.schedule('afterRender', FB.XFBML.parse);
}
});
A script tag
<script type="text/javascript" src="//connect.facebook.net/en_US/sdk.js#xfbml=1&appId=123&version=v2.2"></script>
The root div facebook asks for
<div id="fb-root"></div>
Loading Facebook SDK
import ENV from "my-app/config/environment";
import setupOfflineMode from "my-app/utils/offline-mode";
export function initialize(container, application) {
// offline mode stubs `FB`
if (ENV.offlineMode) { return setupOfflineMode(); }
// Wait for Facebook to load before allowing the application
// to fully boot. This prevents `ReferenceError: FB is not defined`
application.deferReadiness();
var fbAsyncInit = function() {
initFacebook(window.FB);
application.advanceReadiness();
};
loadFacebookSDK();
window.fbAsyncInit = fbAsyncInit;
}
function loadFacebookSDK() {
(function(d, s, id){
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {return;}
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
}
function initFacebook(FB) {
FB.init({
appId: ENV.FB_APP_ID,
status: true,
cookie: true,
xfbml: true,
version: ENV.GRAPH_API_VERSION
});
}
export default {
name: 'facebook',
initialize: initialize
};
Share Links
I think this is all I needed to do; I hope I'm not forgetting something...
I didn't set up a component, so this is just a regular view, but it should work about the same.
<div class="fb-share-button" {{bind-attr data-href=link}} data-type="button"></div>
export default Ember.View.extend({
setupSocialNetworks: function() {
Ember.run.scheduleOnce('afterRender', this, function() {
FB.XFBML.parse();
});
}.on('didInsertElement')
});
UPDATE: Alternate solutions
I think which solution you use really depends on your needs. I'm focusing on a faster time-to-first-render, so I've changed my project to not deferReadiness for the Facebook SDK.
I've been playing with two solutions, again I think it totally depends on your needs.
Load the Facebook SDK in an initializer, but set a global promise for access.
This starts the loading on boot, but allows your application to continue booting without having to wait for Facebook. All calls to the Facebook API need to be accessed through the promise.
I'll share the details of this one if requested, but for now I'll just focus on the next solution:
Load the Facebook SDK only on demand in a service.
As before, all access to the Facebook API will need to go through a promise, but this time it is nicely encapsulated in a service and is only loaded on demand:
// app/services/facebook.js
import Ember from 'ember';
import ENV from "juniper/config/environment";
var computed = Ember.computed;
var RSVP = Ember.RSVP;
var _facebookSDKDeferrable = Ember.RSVP.defer();
var fbAsyncInit = function() {
_initFacebook(window.FB);
_facebookSDKDeferrable.resolve(window.FB);
};
window.fbAsyncInit = fbAsyncInit;
export default Ember.Service.extend({
// Resolves when the Facebook SDK is ready.
//
// Usage:
//
// facebook: Ember.inject.service(),
// foo: function() {
// this.get('facebook.SDK').then(function(FB) {
// // Facebook SDK is ready and FB is a reference to the SDK
// });
// }
SDK: computed.alias('FB'),
FB: computed(function() {
_loadFacebookSDK();
return _facebookSDKDeferrable.promise;
})
// I've also put promisified helpers for Facebook SDK
// methods here.
});
function _loadFacebookSDK() {
(function(d, s, id){
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {return;}
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
}
function _initFacebook(FB) {
FB.init({
appId: ENV.FB_APP_ID,
status: true,
cookie: true,
xfbml: false,
version: ENV.GRAPH_API_VERSION
});
}
Note also that I've set xfbml to false in FB.init. If your share links have been rendered before the SDK gets loaded, FB.init({ xfbml: true }) will "parse" them, and your FB.XFBML.parse() call will do it again. By setting xfbml to false, you ensure that FB.XFBML.parse() will only get called once.

Facebook SDK and rails 4 Turbolinks

I'm having a hard time trying to load fast the javascript Facebook SDK into my rails 4 application. Is there a good way to make it work correctly with turbolinks?
if i add this code on my JS application assets.
It's not working properly due to turbolinks:
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function() {
// init the FB JS SDK
FB.init({
appId : 'YOUR_APP_ID', // App ID from the app dashboard
channelUrl : '//WWW.YOUR_DOMAIN.COM/channel.html', // Channel file for x-domain comms
status : true, // Check Facebook Login status
xfbml : true // Look for social plugins on the page
});
// Additional initialization code such as adding Event Listeners goes here
};
// Load the SDK asynchronously
(function(d, s, id){
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {return;}
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/all.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
</script>
thanks
You will find the proper solution for integrating the Facebook SDK with Turbolinks here :
http://reed.github.io/turbolinks-compatibility/facebook.html
I was having a problem with the Like Box not loading when I navigate between pages using turbo links. My solution was to create a social.js.coffee in my assets/javascripts folder. In this file it simply has
$(document).on 'page:change', ->
FB.init({ status: true, cookie: true, xfbml: true });
I know its a lot to put in it's own file ;-), but the idea was that I know google analytics, twitter, and others will have the same conflicts and this will be a nice place to house those solutions as well.
Quoting this answer
If you prefer to use native Turbolinks 5 events, you can add this script to your Rails assets:
// FacebookSDK
// https://developers.facebook.com/docs/plugins/page-plugin/
(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s);
js.id = id;
js.src = "//connect.facebook.net/ja_JP/sdk.js#xfbml=1&version=v2.8";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk')); // Replace 'facebook-jssdk' with your page id.
// Compatibility with Turbolinks 5
(function($) {
var fbRoot;
function saveFacebookRoot() {
if ($('#fb-root').length) {
fbRoot = $('#fb-root').detach();
}
};
function restoreFacebookRoot() {
if (fbRoot != null) {
if ($('#fb-root').length) {
$('#fb-root').replaceWith(fbRoot);
} else {
$('body').append(fbRoot);
}
}
if (typeof FB !== "undefined" && FB !== null) { // Instance of FacebookSDK
FB.XFBML.parse();
}
};
document.addEventListener('turbolinks:request-start', saveFacebookRoot)
document.addEventListener('turbolinks:load', restoreFacebookRoot)
}(jQuery));
From: https://gist.github.com/6temes/52648dc6b3adbbf05da3942794b97a00
If you're putting your Facebook JS code at the end of your view, use flush in your controller action to ensure it's fully reloaded properly with Turbolinks:
def show
# ...
render :show, flush: true
end
Worked like a charm.
I followed the solution suggested by #gallonallen with some small modification. just created a file called turbo.js with following content:
$(document).on('turbolinks:load', function() {
FB.init({ status: true, cookie: true, xfbml: true });
});
And added //= require turbo in application.js before //= require query and it started working for me. I am using rails 4.2.6 and ruby 2.3.1 with turbo links 5. For me, prior to fix, turbo links was working on my local but not when deployed to staging or prod.

iOS web/native app Facebook Login Popup - FAILS?

I am trying to build a web app that will allow a user to login Facebook. Everything works in Firefox/Chrome/Safari (on the phone/tablet and on OSX).
When the App runs on the tablet (Native UIWebview and Web-app) it loads the first page perfectly.
When the user clicks the "connect with Facebook" button the app loads the Facebook logon page.
After the user logs in (again, in both a Native UIWebview and a web-app) the view turns white hanging on the URL: 'https://www.facebook.com/dialog/permissions.request?_path=permissions.request&app_id=[APP_ID]...' - this seems like it should not happen...
If I restart the app/web-app the user is logged in automatically, and redirected to the success page.
What I think is causing the problem
When you run the web page in the Firefox/Chrome/Safari browsers the Facebook login Dialog pops up as a popup or another tab (the latter on the native Safari browser).
I believe that this is a problem with this popup page and how the Javascript communicates with itself when a successful login takes place. Something with window.close where there is no root page to return to (as the web-app and UIWebview only have one instance of the webview)... maybe?
Failed work-around (UIWebview)
Since the app was hanging up on the previously mentioned URL I decided to add an if statement in shouldStartLoadWithRequest(...) to force the UIWebview to go to the success URL.
It loads the URL, but then before Facebook's Javascript SDK function FB.getLoginStatus function returns 'Connected' (It does return 'Connected' every time I've seen) The function FB.Event.subscribe('auth.logout' function() {...}); is fired.
I don't understand why it is logging the user out, then telling me that the user is connected (logged in) - in that order.
Any Ideas before I embark on trying to build this 100% native (and have to put up with apple's dev account and submitting the app)?
Login Script
<script>(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/all.js#xfbml=1&appId=APP_ID";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>
<script>
var seccond_page = false;
window.fbAsyncInit = function() {
FB.init({
appId : '[APP_ID]',
status : true,
cookie : true,
xfbml : true,
oauth : true
});
FB.Event.subscribe('auth.login', function(response) {
window.location.href = '<?= $success ?>';
});
FB.Event.subscribe('auth.logout', function(response) {
window.location.reload();
});
FB.login(function(response) {
alert(response.status);
if (response.status) {
if (response.status == 'connected') {
window.location.href = '<?= $success ?>';
}
}
}, {scope: 'email, user_likes, user_status, user_birthday, user_location, publish_checkins'});
$(document).on('click', '#fb_login_button', function() {
FB.login();
});
};
</script>
Success Page
<script>
var fb_user_id = '';
var fb_access_token = '';
var user_location = '';
window.fbAsyncInit = function() {
FB.init({
appId : '[APP_ID]',
status : true,
cookie : true,
xfbml : true,
oauth : true
});
FB.getLoginStatus(function(response) {
alert('Response - ' + response.status);
// the auth.logout is fired before the return of this in the failed fix
if (response.status === 'connected') {
if (response.authResponse) {
fb_user_id = response.authResponse.userID
fb_access_token = response.authResponse.accessToken;
}
}
});
FB.Event.subscribe('auth.logout', function(response) {
alert('logout - auth.logout');
// This event is fired before the above function in the failed fix
window.location.href = '<?= site_url('fb_login'); ?>';
});
FB.Event.subscribe('edge.create', function(response){
if (response == '<?= $like_url ?>') {
//action
}
});
};
</script>
All pages have the meta tag: <meta name="apple-mobile-web-app-capable" content="yes">
Facebook calls auth.logout just before auth.login for reasons not clear to me. You should inspect the response parameter before assuming that the user really has been logged out. Facebook docs state:
auth.logout - fired when the user logs out. The response object passed into the callback function looks like:
{
status: "", /* Current status of the session */
}
If you execute your logout handling only if response.status is really "", you may find that during login, it calls auth.login listeners immediately after calling the auth.logout listener. Your current auth.logout handling prevents you from noticing this, because the page reload stops JS and ajax executions.

FB.login popup on mobile web doesn't auto close once logged in

I have a Facebook connect site and am having issues with the Facebook login part on mobile browsers (ie: iPhone Safari, etc). Whenever I click the login button, it opens a new tab in Safari which takes me to a URL like this: https://s-static.ak.fbcdn.net/connect/xd_proxy.php... followed by a bunch of extra hashes.
The problem is, this page doesn't auto close and go back to my app. I have to manually close it and then go back. The login process works fine and the other page has already refreshed and loaded, but I can't figure out why it's not auto closing the XD Proxy page.
I've followed all the tutorials on Facebook for setting up the javascript code. I'm using FB.login() to actually login. It works flawlessly on the desktop. I'm wondering if this is a bug in Facebook's javascript or not, but I can't seem to figure it out. Any ideas would be very helpful.
Here is the code I'm using, for reference:
<script>
window.fbAsyncInit = function() {
FB.init({
appId: "APP_ID",
status: true,
cookie: true,
oauth: true,
xfbml: true
});
};
(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/all.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
</script>
<button onclick="loginToFB();" type="button" class="fb-login-button">Login with Facebook</button>
<script type="text/javascript">
function loginToFB(next) {
FB.login(function(response) {
if (response.authResponse) {
window.location = '/facebook';
}
}, {scope: 'SCOPE_STRING'});
}
</script>
Thanks!
Try first calling the getLoginStatus() function and don't do FB.login() if the user is already logged in.

Resources