At the Forge - Working with Facebook

 in
Writing a Facebook application? It's easy to retrieve information about Facebook users and their friends as well as display it, using the RFacebook plugin for Rails.
fbsession

Much of the Facebook developer documentation has to do with the ways in which you can retrieve information about current users and their friends. However, we will ignore that for now, because RFacebook pulls all of that together, as well as the authentication tokens that you need, into a single fbsession function. For example, you can write:


@friend_uids = fbsession.friends_get.uid_list

and @friend_uids will be populated with a list of the user IDs for the current user's friends. We even can display this:


@friend_uids = fbsession.friends_get.uid_list
render :text => "<p>#{@friend_uids.join(', ')}</p>"
return

To review, fbsession is our handle into the Facebook API. fbsession.friends_get is not merely an array of friends; rather, it is an object of type Facepricot. If this seems like an odd name to you, consider that a popular XML-parsing tool for Ruby is called Hpricot. As you can imagine, Facepricot is a Facebook-specific extension of Hpricot, which allows you to navigate through the response as if it were an Hpricot document or use Facebook-specific shortcuts. One such shortcut is seen above, as the uid_list method. Although we also could have retrieved the list of friend uids using Hpricot, this is more natural, as well as more readable and terse.

Indeed, we also could have written the above code as:


@friend_uids = fbsession.friends_get.search("//uid").map{|xmlnode|
xmlnode.inner_html}
render :text => @friend_uids.join(', ')
return

But, unless you're doing something particularly complicated, you probably don't want to that.

Displaying Friends

Once we have retrieved the user's friends' uids, we can ask Facebook to give us some information about each one, using fbsession's users_getInfo method:


@friendsInfo =
  fbsession.users_getInfo(:uids => @friend_uids,
                          :fields => ["first_name", "last_name"])

Notice that we're using instance variables (names starting with @) rather than plain-old variables. This ensures that the variables will be visible within our views. For example, we could render the above within our controller:


@friends_info =
  fbsession.users_getInfo(:uids => @friend_uids,
                          :fields => ["first_name", "last_name"])

output = ""
@friends_info.user_list.each do |friend|
  output << "<p>#{friend.first_name} #{friend.last_name}</p>\n"
end

render :text => output
return

In the first line, we use fbsession.users_getInfo to invoke the getInfo method from the Facebook API. (Indeed, fbsession provides us with an interface to the entire Facebook API, albeit with some character translation along the way.) users_getInfo takes two parameters: a list of user IDs about which to retrieve information and then the fields we want to retrieve about them.

For example, perhaps we want to find out whether each of our friends is male or female, as well as how many messages they have on their wall. We can do this by modifying our users_getInfo query, as well as by changing our output:


@friends_info =
  fbsession.users_getInfo(:uids => @friend_uids,
                          :fields => ["first_name", "last_name",
                                      "sex", "wall_count"])

output = ""
@friends_info.user_list.each do |friend|
  output << "<p>#{friend.first_name} #{friend.last_name}
(#{friend.sex}), with #{friend.wall_count} hits on their wall.</p>\n"
end

render :text => output
return

Sure enough, this produces a list of our friends, along with their stated sex and the number of hits on their wall. Behind the scenes, our call to users_getInfo is sending a request to Facebook's servers. Facebook authenticates our request and then sends a response. Although the response is in XML, the Facepricot object provides us with some convenience functions that make it easy to work with what it provides.

A Nicer Display

The above code might work, but you would be hard-pressed to say that it was elegant. If nothing else, Rails programmers are consistent about their praise for the MVC paradigm in Web development. That is, you want to have a clear separation between the back-end data model, the controller that handles business logic and the way in which displayed items are rendered on the user's view or screen.

Luckily, it's easy to modify the way in which these things are displayed. Rather than collecting the textual output in a variable (named output in our above examples), we can define our entire method as:


def facebook
  @friend_uids = fbsession.friends_get.uid_list

  @friends_info =
    fbsession.users_getInfo(:uids => @friend_uids,
                            :fields => ["first_name", "last_name",
                                        "sex", "wall_count"])

end

We then create (or modify, if you still have your view from last time) facebook.rhtml, which looks like:


<% @friends_info.user_list.each do |userInfo| %>
<ul>
      <li><%= userInfo.first_name %> <%= userInfo.last_name %></li>
</ul>
<% end %>

In other words, we iterate through each element in our list of friends, pulling out their names. We can use all the information we have captured, not just the names:


<% @friends_info.user_list.each do |userInfo| %>
<ul>
      <li><%= userInfo.first_name %> <%= userInfo.last_name %> (<%=
userInfo.sex %>), wall count <%= userInfo.wall_count %></li>
</ul>
<% end %>

But, wait one moment—we can do even better than this! Because we are rendering things within Facebook, we can take advantage of FBML, the Facebook Markup Language. FBML is an extended subset of HTML, which is a fancy way of saying that it adds some Facebook-specific tags while removing some standard HTML tags. In any event, it allows us to create a variety of lists, interfaces and functionality that are common to Facebook applications and include them in our applications. For example, let's change our view to the following:


<% @friends_info.user_list.each do |userInfo| %>
<ul>
      <li><fb:name uid="<%= userInfo.uid -%>" target="_blank"
/><fb:profile-pic\
 uid="<%= userInfo.uid -%>" linked="true" /></li>
</ul>
<% end %>

Now we're iterating over the same list. But, instead of rendering things directly from Ruby, we're using Ruby to pass the friend's user ID to FBML tags. Each FBML tag takes one or more arguments, passed in the form of HTML/XML attributes. In this case, we have used two FBML tags: fb:name, which displays a user's name, and fb:profile-pic, which displays the user's picture.

As you can see, we have passed each tag the uid attribute, then used some rhtml to bring in the user's ID. We also have passed the linked attribute to indicate that the picture should be a link to the user's profile. (The name is linked to the profile by default, so we don't need to say anything about that.) I have been quite impressed by the number and types of attributes that Facebook's developer API provides, going so far as to let us indicate whether we want to have the name rendered in the possessive form.

______________________

Webinar
One Click, Universal Protection: Implementing Centralized Security Policies on Linux Systems

As Linux continues to play an ever increasing role in corporate data centers and institutions, ensuring the integrity and protection of these systems must be a priority. With 60% of the world's websites and an increasing share of organization's mission-critical workloads running on Linux, failing to stop malware and other advanced threats on Linux can increasingly impact an organization's reputation and bottom line.

Learn More

Sponsored by Bit9

Webinar
Linux Backup and Recovery Webinar

Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.

In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.

Learn More

Sponsored by Storix