Integrating Facebook into Rails

Recently, I integrated facebook’s new Graph API into Noteleaf. Though it’s far far easier than the old API, which almost didn’t warrant a blog post. However, authorization took a little bit of figuring out, so I thought I’d share.

If you’re using the languages blessed by Facebook, such as PHP, Javascript, Python, Objective-C and Java Android, then there’s already an SDK for you.

However, as a rubyist, we were on our own. Since we’re using Authlogic, we should be able to find a plugin for authenticating facebook.

On the Authlogic docs, it has authlogic_facebook_connect listed. It also depends on the most popular ruby gem for facebook integration, facebooker. However, facebooker’s documentation is shabby and the tutorials are out of date. I didn’t want to be digging around in something that wasn’t our core value proposition. So I didn’t end up going that route.

I was digging for alternatives, but in all the wrong places. It wasn’t until I was reading the facebook api docs more carefully, that I realized I should be looking for an OAuth2 module for Authlogic. After that, it was a breeze.

The instructions for authlogic_oauth2 are pretty clear, but here’s some tips. Beyond the instructions in authlogic_oauth2, make sure you set the oauth2_scope to request offline_access. If you don’t, when the user’s facebook session expires, your oauth_token that you stored in the user’s database will be expired. That means that after a while, the user won’t be able to log back in without requesting another token.

class UserSession < Authlogic::Session::Base
  oauth2_scope          "offline_access,email"
end

And if you do store the user’s facebook id locally, make sure it’s a big int.

class AddFacebookIdToUser < ActiveRecord::Migration
  def self.up
    add_column :users, :facebook_id, :bigint, :limit => 8
  end

  def self.down
    remove_column :users, :facebook_id
  end
end

which you can subsequently set in a before_create filter in User model.

class User < ActiveRecord::Base
  before_create :populate_oauth2_user

  private
  def populate_oauth2_user
    return if oauth2_token.blank?

    response = oauth2_access.get('/me')
    user_data = JSON.parse(response)
    if !user_data['id'].blank?
      self.facebook_id = user_data['id']
    end
  end
end

You may also want to consider using the provided javascript SDK. That way, you’d be able to load your page first, and have the client’s browser request the rest of the facebook data, so it appears you page loads faster.

Boosting my social memory

I’ve changed what I’m working on, as I decided to table Graphbug as a side project. Everyone said public data would be a good thing for lay-people to browse through easily, but no one could specifically think of what datasets they’d want. Like going to the dentist, it’s something that’s good for other people, but not themselves. In hindsight, I should have picked data to visualize for apartment hunting and moving as the niche problem to solve. Otherwise, I was trying to boil an ocean.

But that’s ok, as I’ve moved on to found a startup to do something I’ve really wanted for a long long time. We’re working on Noteleaf, something to boost your social memory by making it easy to take notes and follow up on the people you know and meet.

http://noteleaf.com

I have terrible social memory. It’s not just not merely remembering people’s names. That can be done with a little bit of effort and mental hacks. I can’t remember what other people are doing in their lives, whether they’re graduating, moving, or looking for a job. I can’t remember what the name of their kids are, their girlfriend, or fiancé. 

One fine day in May, I called my friend Amy up and said, “Congratulations!”. She replied enthusiastically, but puzzled: “Thanks! But for what?” I told her, “For graduating dental school.” She laughed, “Ahh, thanks, but I graduated last year, and you called me then to congratulate me too.” 

It’s not that I don’t care. I just can’t remember. I have disparate groups of friends, so I don’t get gossip about other friends to remind me of what they’re doing. My friend ranges from college-aged to recent parents with kids. With everyone in different stages of life, I can’t keep track. I have enough things to keep track in my own life that it’s hard to have bandwidth to think of others.

Thoughtfulness has to be both relevant and timely. Relevant, because it makes no sense to congratulate someone on their new job when they are still at their old one. Timely, because wishing someone happy birthday on a day that’s not their birthday doesn’t have the same effect.

We wrote Noteleaf to help us do both. By taking simple notes about others, you can recall what you talked to them about last time and start right where you two left off. And by scheduling automatic followups you can be thoughtful on your own time, and they get it when it’s timely for them.

Facebook has been nice in getting news about friends old and new. However, not everything you’d want to remember about them comes on the news feed. There’s a transient nature to the news feed, that chances are, you won’t remember whether a friend left for vacation this week or next, and you meant to give them some travel tips.

With business contacts, you may not even be facebook friends. While important, you may meet them even less, so the details of their lives are even more fleeting. It’s a leg up to getting things done, when you can remember who they are and what’s important to them.

Noteleaf is still in closed beta for the time being, but just put yourself on our email list, and we’ll let you know when we open the gates. In the meanwhile, we also started a noteleaf blog.

For all of our busy lives, I think it’s important that we are involved in the lives of those we care about, and keep making connections to new and interesting people. Because beyond the glory of work and career, the trappings of fame and accolades, and enticement of money and prestige, deep connections to people we care about, and giving back and helping to others, is one aspect of life that fulfills us and makes us whole.

How to generate forms in rails helpers

This is more of a note to myself than anything, since I find myself having to generate forms from helpers in Rails every once in a while. This is for Rails 2.3.5. I don’t know if Rails 3 has this problem.

I wrote my own in-place editor for model fields, and it generates a form through a helper.

# used internally to generate the form for the en_place editor
def en_place_form(record_or_array, field_name, 
                  options = {}, html_options = {})
  # process the options, and other misc details
  form_block = proc do
    form_for(record_or_array, :html => html_options) do |f|
      concat(f.text_field field_name, :class => "en_place")
      concat(f.submit "Update")
    end      
  end
  is_haml? ? capture_haml(&form_block) : capture(&form_block)
end

All you have to do is capture a block that calls form_for or form_tag. And then inside of the form, you can to call concat on the fields that you want inside of the form.

Then lastly, you have to capture the block. If you’re using haml, you have to call capture_haml() instead.

A left merge versus a right merge

Recently, I found out that you can set the default winner in a merge for a hash. I wasn’t going to write about it since I figured it was pretty basic. But then again, I hadn’t written in a while. Been busy. So something easy to get me back on the wagon.

I’ll call it a left merge and a right merge. Let’s say we have some options, like default options and new options in a method, and we want merge them together, where options override default options, but you store it into options.

# some options
default_opts = { :a => 1, :b => 2 }
opts = { :b => 3, :c => 4 }

Well, the normal way of merging things won’t work:

# the normal default merge
opts.merge!(default_opt) # => { :a => 1, :b => 2, :c => 4 }

Well, that’s not right. We want the default options to be overridden by the new options and store it in the opts variable. We could do it like this:

# one way of doing things
opts = default_opts.merge(opts) # => { :a => 1, :b => 3, :c => 4 }

But then here’s another

# the other merge
opts.merge!(default_opts) { |k,o| o } # => { :a => 1, :b => 3, :c => 4 }

Yay!

BrowserCouch is CouchDb for browsers

BrowserCouch Documentation

BrowserCouch is an attempt at an
in-browser MapReduce
implementation. It’s written entirely in JavaScript and intended
to work on all browsers, gracefully upgrading when support for
better efficiency or feature set is detected.

Not coincidentally, this library is intended to mimic the
functionality
of CouchDB on
the client-side, and may even support integration with CouchDB in
the future.

Why?

This prototype is intended as a response to Vladimir
Vukićević’s blog post
entitled HTML5
Web Storage and SQL
. A CouchDB-like API seems like a nice
solution to persistent storage on the Web because so many of its
semantics are delegated out to the JavaScript language, which
makes it potentially easy to standardize. Furthermore, the
MapReduce paradigm also naturally takes advantage of multiple
processor cores—something that is increasingly common in
today’s computing devices.

Things to do

To learn how to use BrowserCouch, check out the
work-in-progress tutorial.

Aside from that, you can run the test suite and the semi-large data set test, though they’re not
particularly exciting. In the future, we’d like to make CouchDB’s
Futon
client work entirely using BrowserCouch as its backend instead of
a CouchDB server, but that’s a ways away.

If you’d like to see more code samples of what the BrowserCouch
API currently looks like, check out the annotated source code for the test suite.
You can also read the primary source code documentation
for more on BrowserCouch’s implementation.

This is really awesome. I thought about doing this, but figured it was a massive undertaking. I’m glad someone’s doing it. CouchDb’s replication features (while not implemented yet in BrowserCouch), is something to really look forward to, especially if it’s available for mobile browsers.