Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a Facebook Credits Ruby On Rails gem out there yet? Or ruby version of their Facebook Credits sample app?

I am wanting to implement Facebook Credits in my Facebook app. Does anyone know of a version of the Facebook Credits sample app available in Ruby on Rails? Has anybody made a gem for this yet? If I find one I'll link below...

like image 330
Richard Jordan Avatar asked Jan 28 '11 01:01

Richard Jordan


1 Answers

Here is my code taking the FB example and RORing it:

require 'facebook_signed_request.rb'

class FacebookCreditsController < ApplicationController

skip_before_filter :verify_authenticity_token
layout nil

  def index
    facebook_request = FacebookSignedRequest.new(request.params['signed_request'])
    data = { "content" => {} }
    # handle invalid request
    if !facebook_request.valid?
      return
    end

    signed_request = facebook_request.signed_request

    # handle invalid signed request
    if signed_request.nil?
      return
    end

    method = request.params['method']

    order_id = request.params['order_id']

    # second state response from facebook
    if method == 'payments_status_update'
      status = request.params['status']

      if status == 'placed'
        next_state = 'settled'
        data['content']['status'] = next_state
      elsif status == 'settled'
        redirect_to '/lots'
        return
      end

      # compose returning data array_change_key_case
      data['content']['order_id'] = order_id

    # first stage response from facebook
    elsif method == 'payments_get_items'

      order_info = request.params['order_info']

      item = JSON.parse(order_info)
      item['price'] = item['price'].to_i

      # for url fields, if not prefixed by http://, prefix them
      url_key = [ 'product_url', 'image_url' ]
      url_key.each do |key|
        if item[key][0..6] != 'http://'
          item[key] = "http://#{item[key]}"
        end
      end

      # if payload['test_mode']
      if request.params['test_mode']
        update_keys = ['title', 'description']
        update_keys.each do |key|
            item[key] = '[Test Mode] ' + item[key]
        end
      end

      data['content'] = [item]  
    end

    data['method'] = method

    render :json => data
  end

end

Then in addition to this there is:

require 'base64'
require 'json'
require 'openssl'

class FacebookSignedRequest

  attr_reader :signed_request

  def initialize(signed_request)
    @signed_request = signed_request
  end

  def base64_url_decode str
    encoded_str = str.gsub('-','+').gsub('_','/')
    encoded_str += '=' while !(encoded_str.size % 4).zero?
    Base64.decode64(encoded_str)
  end

  def valid?
    # TODO: move it to some configuration
    secret = " << my secret is here >>"

    # decode data
    encoded_sig, payload = signed_request.split('.')
    sig = base64_url_decode(encoded_sig).unpack("H*")[0]
    data = JSON.parse base64_url_decode(payload)

    if data['algorithm'].to_s.upcase != 'HMAC-SHA256'
    # Rails.logger.error 'Unknown algorithm. Expected HMAC-SHA256'
      return false
    end

    #check sig
    expected_sig = OpenSSL::HMAC.hexdigest('sha256', secret, payload)
    if expected_sig != sig
    # Rails.logger.error 'Bad Signed JSON signature!'
      return false
    end

    data
  end

I don't know if this helps anyone else but it's all working for me. Sorry for taking so long to remember to come back and post my working code...

View related code as requested:

#view
<%= javascript_include_tag "premium_signup" %>
<script type="text/javascript">
    $(document).ready(function() {
        $('#premium_signup_button').click(function() {
            signupAsPremiumMember('Premium Membership', 'Create unlimited auctions with no extra charge at all for 1 year.', "1", '', '');
        });
    });
</script>
...
<button id="premium_signup_button">Signup as a premium member</button>

#premium_signup.js
function signupAsPremiumMember(title, desc, price, imageURL, productURL) {
var order_info = {
    "title": title,
    "description": desc,
    "price": price,
    "image_url": imageURL,
    "product_url": productURL
};

var payload = {
    "method": 'pay',
    "order_info": order_info,
    "purchase_type": 'item'
};

console.log(FB.ui(payload, facebookPurchaseCompletionCallback));
}

function facebookPurchaseCompletionCallback(data) {
    if (data['order_id']) {
        console.log(data['order_id']);
    }
    else if (data['error_code']) {
        console.log(data['error_code']);
    }
    else {
        console.log("failed");
    }
}

#in the layout
#in head
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script src="http://connect.facebook.net/en_US/all.js"></script>
<%= javascript_include_tag 'application' %>
#in body
  <div id="fb-root"></div>
    <script>
      FB.init({
        appId  : '############',
        status : true, // check login status
        cookie : true, // enable cookies to allow the server to access the session
        xfbml  : true  // parse XFBML
      });

Now all of this is coming from a guy who sat down and learned to program in Ruby On Rails with as little supporting Javascript knowledge as I can get away with, in about 12 weeks last year with a few more weeks thrown in this year for good measure. I say that by way of caution - the code I've posted might be garbage... but it works :-)

And if anyone actually finds any of this useful a VOTE UP on the answer would be appreciated - just sayin' :-)

like image 71
Richard Jordan Avatar answered Sep 18 '22 18:09

Richard Jordan