FOAF is an RDF spec for describing people and the relationships between them. I thought FOAF had mostly died and been replaced by hcard/XFN. However, it looks like FOAF is going to make a come back as one of the technologies that people build their OpenSocial APIs on top of. So I decided to add it to CrowdVine. You’d think this would be simple but I couldn’t find anyone who described it clearly.
Define a MimeType in
config/initializers/mime_types.rb so that we can use
respond_to to implement FOAF as a second view on on existing profile page. This file is new in Rails 2.0, otherwise it would have gone in
environment.rb. I’ve seen FOAF returned as either “application/rdf+xml” or “text/xml.” I don’t know the repercussions of choosing one over the other.
If your profile urls are something like
/profiles/42 then we want the FOAF url to be
/profile/42.rdf. I was already using
map.resources :profiles which set up that route for me. However, it didn’t create a named route that would take the format (rdf), so let’s do that:
map.foaf 'profiles/show/:id.:format', :controller => "profiles", :action => "show"
Now let’s go into our controller and use
respond_to to tell our action to choose a template based on the requested format.
respond_to do |format| format.html format.rdf end
Now you’re ready for a FOAF template. If your profile template is named
show.rhtml) then you want to create a new template called
show.rdf.builder. The file name lets Rails know that it’s the template that should be used for RDF requests and that the template should be parsed with the builder template engine (good for XML templates). Below is the template I used. You’ll need to make modifications based on the meta data you have for your users.
xml.instruct! xml.rdf(:RDF, "xmlns:rdf" => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", "xmlns:foaf" => "http://xmlns.com/foaf/0.1/", "xmlns:rdfs" =>"http://www.w3.org/2000/01/rdf-schema#") do xml.foaf(:Person) do xml.foaf(:name, @person.name) xml.foaf(:mbox_sha1sum, Digest::SHA1.hexdigest("mailto:" + @person.email)) xml.foaf(:homepage, "rdf:resource" => profile_url(@person)) xml.foaf(:depiction, "rdf:resource" => "http://" + request.host_with_port + url_for_file_column("person", "image")) @person.friends.each do |friend| xml.foaf(:knows) do xml.foaf(:Person) do xml.foaf(:name, friend.name) xml.rdfs(:seeAlso, "rdf:resource" => foaf_url(friend, :rdf)) end end end end end
At this point you should be able to go to a URL like
/profile/1.rdf and get back a FOAF file. If you don’t get anything back, then that means I explained something wrong. Once you are getting something back you should run the output through a FOAF validator. Unfortunately the validator everyone points to, FOAF Lint, doesn’t seem to be working. Instead, you should try the W3C RDF Validator and FOAF Explorer. FOAF Explorer lets you walk the FOAF graph. It’s really cool and I wasn’t confident I’d gotten the FOAF right until I’d seen it in Explorer.
Now that you have working FOAF, you need to make it auto-discoverable. You want to to get something in the HEAD section of your profile pages that looks like this:
<link rel="meta" type="application/rdf+xml" title="FOAF" href="http://example.com/profiles/id.rdf"/>
Since the FOAF file is only going to be auto-discoverable on profile pages you can’t just hard code that into your layout. I used the
content_for helper to get around that. You define the auto-discovery link in your profile template with code like this:
<% content_for("header") do %> <link href="<%=foaf_url(@profile, :rdf) %>" rel="meta" type="application/rdf+xml" title="FOAF" /> <% end %>
Then you put a line in the
HEAD section of your layout to display it.
<%= yield :header %>