Friday, February 12, 2010

Facebook Connect using Facebooker on Heroku

Recently I had a chance to create a Facebook Connect Rails application. I did not have any public server on which I could host my application so I chose Heroku. We need to host our application on a public server so that we can listen the response of Facebook when we request its servers.

One actually does not need to use heroku or other public server to develop a Facebook application. We can open up our own development machine to internet by port forwarding ans listen the response. However I did not have much time to do all this stuff and decided to host the application on heroku.

So lets get our hands wet with code and stuff.

Goals


In this post we are going to implement user authentication mechanism in a Rails application using Facebook Connect. We would use Authlogic and authlogic facebook connect plugin. This makes life easier for us.

Create a Rails application on heroku


First create a Rails application on your machine and gitify it by running following commands.



First command creates a Rails application named katana and third one initialises a git repository and makes "First Commit".

Now we will push this application to heroku server. First create an account on heroku if you have not done it yet. Now run following commands to push your application to heroku.



First we install the heroku gem and then we upload this application to heroku servers. "$ heroku create" might ask for your heroku credentials.

Installing required Gems and plugins


Now we will install Facebooker, Authlogic gems and authlogic facebook connect plugin in our application.

Heroku requires you to use bundler for installing gems in your application. Read their documentation on gems to know how to do this.

Now create a 'Gemfile' in your application root like following.



The first line above is specific to heroku. Do read heroku documentation to know more about this. Other lines tell the application to install specific gems and use them.

Now install authlogic facebook connect plugin to your application. Give following command to install the plugin.



After the plugin is installed, make a commit and push the changes to heroku by running ':~/katna$ git push heroku master'. After doing this, you are ready to implement user authentication.

User authentication using Facebook Connect


Now create User model. Make your users table migration as following.



'facebook_session_key' and 'facebook_uid' are there to hold the facebook session key of the currently logged in user and his id at the facebook. You must have noticed that 'facebook_uid' column has its limit set to 8. This is because facebook_uid is a big int. On heroku, we have Postgres as default database engine. Postgres will bark at us if we do not provide the limit option. The default integer column in Postgres does not support big ints.

Crate your user model as following.



'acts_as_authentic' will tell authlogic to use this model for authentication purposes. 'before_connect' hook is provided to us be authlogic facebook connect plugin. It can be used to save some user data when he tries to connect to Facebook from our application.

Now create the UserSession model by running '$ script/generate session user_session' command. This 'session' generator is provided by authlogic. Make your UserSession model look like following.



Second line tells Authlogic to let a user "Sign In" and "Sign Up" using his email. By default it is 'username'.

Now add following lines to your 'application_controller.rb'.



First line will set the facebook_session for each user signed in to the application using Facebook connect. Second line adds a helper to retrieve that session.

Now create UserSessions controller and corresponding views.



When a user tries to sign in using facebook connect, 'create' action of UserSessions controller is invoked. After a successful sign in, he is redirected to 'show' action of DashboardsController.

Now create layout 'application.html.erb'.



'fb_connect_javscript_tag' will link the Facebook's JS api with your application. With this we will be able to use Javascript api function in our application.

'init_fb_connect' will tell our application to use XFBML in our application without any quirks.

Now create 'views/user_sessions/new.html.erb'



'authlogic_facebook_login_button' helper is provided by authlogic facebook connect plugin. It will put a facebook connect button on our Sign Up page. By clicking on this button, a user can Sign into our application using facebook connect.

We will now create Dashboards controller.



Following is view for 'show' action of Dashboards controller.



Now remove 'index.html from your 'public' directory and create your 'config/route.rb' to look like following.



Now run the command ':~/katana$ script/generate xd_receiver'. It will create cross domain scripting bridge between facebook and our application. It will allow both of them to communicate.

Now do a ':~/katana$ git commit' and ':~/katana$ git push heroku master' to deploy application to heroku.

Now before you go check out the application, we have to do some more important tasks to do.

Create a Facebook application


Got to Facebook developers page and set up a new application. If your application is hosted at 'http://app.heroku.com', make following edits to your facebook application.

First, on "Canvas Tab" fill in the "Canvas Page URL" as 'http://apps.facebook.com/{some_name}/'. '{some_name}' in the URL has to have at least seven characters. With this URL, the users of your application can access it on Facebook.

On "Canvas Callback URL", put 'http://app.heroku.com/'. Facebook pulls content for Canvas page from this URL for our application. Note, there has to be a trailing '/' at the end of the URL.

In the "Post-Authorize Redirect URL", put 'http://app.heroku.com/user_session/'. Facebook will POST the response when a user tries to sign into the application using facebook connect and is authenticated at the facebook server. Note, there has to be a trailing '/' at the end of the URL. Since facebook POSTs the response at '/user_session', the response will be received by 'create' action of the UserSessions controller.

Now on the in the "Connect URL" on "Connect Tab" put 'http://app.heroku.com/'. Again note the trailing '/'.

In the "Advanced Tab" make sure that the "Application Type" is "Web" and "Sandbox Mode" is "Enabled".

Now we will tell our facebooker to use this application for Facebook connect.

Facebooker configuration


Create a 'config/facebooker.yml' like following.



Replace and with the keys you got from Facebook. Notice one thing that , and other entries in 'facebooker.yml' are not strings. You just simply copy paste them from application page at facebook.

Now make a commit to the application and deploy the application to heroku. After successful deployment, run :~/katana$ heroku rake db:migrate'.

Go to your 'http://app.heroku.com' and try to sign in using facebook connect.

20 comments:

Colin N. said...

Cool tutorial waseem I think you posted the wrong code snippet for "Following is view for 'show' action of Dashboards controller."

Waseem said...

@Colin You are right I accidentally put the code for dashboards controller. I have corrected that now. Thanks!

Anonymous said...

Thank you for very useful Tutorial, we are building also a Facebook application on the Heroku platform but we are blocked at several steps.

Have you got a complete listing of the commands of this tutorial please?

We have a problem with the gem install command line.
http://docs.heroku.com/gems

Also, we don't know in which file to put the part of the last html.erb piece of code after:
"Following is view for 'show' action of Dashboards controller."

Thank you,

Samuel & Slim from France.

Waseem said...

@Samuel

Above are the steps which I followed to get a running facebook application on Heroku.

Heroku recently changed the way they handled gems. It happened because changes in bundler gem. The information above about installing gems is no longer supported. Please read the heroku gems documentation http://docs.heroku.com/gems and bundler documentation to make it work.

I will update the the article once I get time. :)

If we go the restful way, "Following is view for 'show' action of Dashboards controller" means we need to put that code in 'app/views/dashboards/show.html.erb'

Anonymous said...

Hello again,

We are still blocked, we followed the heroku documentation and your tutorial.
Is it possible to add you in one of our heroku application to see what is going wrong?


Samuel & Slim

Waseem said...

@Samuel sure you can add me. Try contacting me through my Linked in account.

Unknown said...

Nice tutorial Waseem. Got the furthest with FBconnect with your tutorial.

I'm facing one more issue, after logging in, dashboard does not load - the heroku logs state the following :

NoMethodError (undefined method `login_required' for #<DashboardsController

Any ideas?

Thanks

Unknown said...

Full error message is - (which doesn't seem to suggest that it was anything from your scripts - are there anything else that you include for authlogic?)

/home/heroku_rack/lib/static_assets.rb:9:in `call'
/home/heroku_rack/lib/last_access.rb:25:in `call'
/home/heroku_rack/lib/date_header.rb:14:in `call'
thin (1.0.1) lib/thin/connection.rb:80:in `pre_process'
thin (1.0.1) lib/thin/connection.rb:78:in `catch'
thin (1.0.1) lib/thin/connection.rb:78:in `pre_process'
thin (1.0.1) lib/thin/connection.rb:57:in `process'
thin (1.0.1) lib/thin/connection.rb:42:in `receive_data'
eventmachine (0.12.6) lib/eventmachine.rb:240:in `run_machine'
eventmachine (0.12.6) lib/eventmachine.rb:240:in `run'
thin (1.0.1) lib/thin/backends/base.rb:57:in `start'
thin (1.0.1) lib/thin/server.rb:150:in `start'
thin (1.0.1) lib/thin/controllers/controller.rb:80:in `start'
thin (1.0.1) lib/thin/runner.rb:173:in `send'
thin (1.0.1) lib/thin/runner.rb:173:in `run_command'
thin (1.0.1) lib/thin/runner.rb:139:in `run!'
thin (1.0.1) bin/thin:6
/usr/local/bin/thin:20:in `load'
/usr/local/bin/thin:20

Anonymous said...

Hello Euro,

we have an "ActionController::InvalidAuthenticityToken" error and an other one as you can see on our application: http://sliimysing.heroku.com

Any ideas?

Thanks

Waseem said...

@Euro you can remove the call to before_filter login_required from different controllers.

Jonidreas said...

Hi Waseem, great tutorial. I have not run through it all but I wanted to know whether you thought Facebooker was the best way to have a rails app connect to facebook.

Is is better than using http://github.com/kaiwren/wrest/blob/master/examples/facebook.rb or even the Javascript API for facebook.

Waseem said...

@Jonidreas Thanks!

When I started integrating Facebook connect in my application, only two Ruby libraries were available to be used. The first one was RFacebooker and second was Facebooker. I searched here and there and community suggested me to use Facebooker since it was still under active development that time.

Whether it was a best way or not? I don't know. I guess it solved all of my problems at that time that is why I used it. And the best way to implement something, depends upon your use case IMHO. It was a perfect fit for my use case. I not only intended to implement facebook connect but also use its old REST api to fetch information.

Lately Facebook has released its Open Graph API. And Facebooker does not support the Open Graph API. This fact also makes it a weak option for new developers to use in their projects. There are options like Facebooker2, Mogli, Koala and rest-graph to be used.

Thanks for sharing Wrest. I never knew it existed. Wrest is way too simple to solve my problems.

The Facebook Javascript API is good for you only if you do not intend to request data from Facebook servers and add some value to it before serving it to your users. Addition of value to the data is best done server side.To add value to this data, read from Facebook server, one need to use old REST API or Open Graph API or both.

Unknown said...

Hi waseem,

Thanks for this tutorial. What I currently need is a feature to post messages from rails application to facebook wall. currently my application page accessible to anybody and anybody can post message there and then there should be a button to post this message to facebook wall.when the user clicks on that button, facebook login details should be asked if the user is not alreadyy logged in facebook and should post the message. If the user is already logged into facebook, it will just post the message to facebook wall after confirmation. How can I do this? I have tried with facebooker plugin and was able to place the facebook connect button in my page and was able to connect to facebook. But I don't know how to place a post button and how to post messages. Any help on this?

Waseem said...

@Anu There are two ways you can post a message to a user's facebook wall. First by making a POST request to https://graph.facebook.com/me/feed. To implement this method, you will have to use some wrapper method made available by facebooker. See the bottom of the page at facebook post documentation. It has an example. You should consult facebooker's documentation for the name of the wrapper method.

The second way is to use FB.ui javascript method made available by facebook js library. I think you need to use this. There is also this documentation that has example of how to make a post to a facebook user's wall.

Pablo said...

Found your post trying to get facebooker to work. Very helpful tutorial although I haven't succeeded yet. I'm getting:

You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.+

With this at the top of the trace:
/Library/Ruby/Gems/1.8/gems/facebooker-1.0.75/lib/facebooker/rails/controller.rb:125:in `fb_cookie_prefix'
/Library/Ruby/Gems/1.8/gems/facebooker-1.0.75/lib/facebooker/rails/controller.rb:129:in `fb_cookie_names'

But hopefully I can get it worked out soon. I was glad to see your post was recently written. Too many things I'm finding are very out of date. What version of rails did you develop this with, out of curiosity?

Thanks again.
-Pablo

Pablo said...

Replying to my own comment, since i solved the issue. facebooker.yml was missing which was causing the error I was getting. (For anyone who finds this page because of my comment).
-Pablo

Waseem said...

@Pablo I will suggest not to use this tutorial. Facebook developer APIs have changed a lot since it was written. I will suggest you to use something much recent.

Pablo said...

It seems to mostly work. Right now i'm just having an issue where facebooker always says the session is expired (can't find any good solutions). I think your tutorial is the most recent one I've seen.

Love open source, hate how awful the documentation is ;)

Pablo said...

Last post from me on the subject.

https://github.com/sowenjub/authlogic_facebook_connect

I followed you advice, and I got this to work much more easily! Your tutorial will (I think) help people with the facebook setup side of things.

Thank you for being a kind host, Waseem.
-Pablo

tuxdna said...

Excellent post!