Sunday, January 5, 2014

Google+ Sign-in flow with Rails4 and CoffeeScript

Using Google+ Sign-In API anyone add extra feature to their site to connect more people through those user who are all do sign-in with their Google+ credential.

Google has three different client-side implementation of their Google+ Sign-In. Those are:
  • HTML buttons
  • Button rendered with JavaScript
  • Initiate the sign-in flow with JavaScript
I have used the third implementation with Rails4 and CoffeeScript. Let's see how it works. Before going into deep, you have to create a project for your application in Google API Console. After that you will get following details from your new Google project.
  • clientid: Client ID for web application
  • cookiepolicy: For us default value is: 'single_host_origin'
  • requestvisibleactions: For us default value is: 'http://schemas.google.com/AddActivity'
  • scope: For us default value is 'https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.email'
I have put above data inside my <a> tag for Google+ sign-in logo. Like this way:

<%= link_to image_tag('Sign-in-logo-path', alt: 'Google+'), '#', 
       id: 'connect-gplus', 
       'data-clientid' => 'MyClientID', 
       'data-cookiepolicy' => 'DEFAULT', 
       'data-requestvisibleactions' => 'DEFAULT', 
       'data-scope' => 'DEFAULT' %>
Rest of the things you have to handle through your CoffeeScripting. I have created three coffeescript fucntions under namespace "AppSocialSession":
  1. init
  2. initSessionCreate
  3. initGooglePlusAuth
1. "init" function I am calling from "document.ready" function. Like:

(($) ->
  App.SocialSession = {} if typeof (App.SocialSession) is "undefined"
  ...........

  $(document).ready ->
    App.SocialSession.init()
) jQuery
2. "initSessionCreate" function, I have used for calling my SessionsController's "create" method which will actually create session for signed-in user.

(($) ->
  App.SocialSession = {} if typeof (App.SocialSession) is "undefined"
  ...........

    initSessionCreate: (profileDetails) ->
      $.ajax
        url: "/create"
        type: "POST"
        data: profileDetails
        success: (response) ->
          window.location.assign(response.redirect_url) unless response.redirect_url is "undefined"


  $(document).ready ->
    App.SocialSession.init()
) jQuery
3. "initGooglePlusAuth" function is actually initializing Google+ API and binding API callback function "googleSignInCallback" on click event of Google+ sign-in logo.
(($) ->
  App.SocialSession = {} if typeof (App.SocialSession) is "undefined"

  App.SocialSession =
    init: ->
      @initGooglePlusAuth()

    initSessionCreate: (profileDetails) ->
      $.ajax
        url: "/create"
        type: "POST"
        data: profileDetails
        success: (response) ->
          window.location.assign(response.redirect_url) unless response.redirect_url is "undefined"

    initGooglePlusAuth: ->
      self = this
      googlePlusLink = $(".social-signin a#connect-gplus")
      defaultOptions =
        clientid: googlePlusLink.attr("data-clientid")
        cookiepolicy: googlePlusLink.attr("data-cookiepolicy")
        requestvisibleactions: googlePlusLink.attr("data-requestvisibleactions")
        scope: googlePlusLink.attr("data-scope")

      if googlePlusLink.size() > 0
        $.ajax
          url: "#{window.location.protocol}//apis.google.com/js/client:plusone.js"
          dataType: "script"
          cache: true

        googleSignInCallback = (authResult) ->
          if authResult
            if authResult.status.signed_in
              gapi.auth.setToken(authResult)
              gapi.client.load "plus", "v1", ->
                gPlusProfileRequest = gapi.client.plus.people.get(
                  userId: "me"
                )
                gPlusProfileRequest.execute (gPlusProfile) ->
                  gpUserParams =
                    gp_session:
                      identifier: gPlusProfile.id
                      first_name: gPlusProfile.name.givenName
                      last_name: gPlusProfile.name.familyName
                      username: gPlusProfile.emails[0].value
                      email: gPlusProfile.emails[0].value
                      verified: gPlusProfile.isPlusUser
                  self.initSessionCreate gpUserParams
            else
              console.log "An error occurred"
              return
          else
            console.log "Empty authResult"
            return

        googlePlusLink.bind "click", (e) ->
          e.preventDefault()
          gapi.auth.signIn $.extend(defaultOptions,
            callback: googleSignInCallback
          )


  $(document).ready ->
    App.SocialSession.init()
) jQuery