Friends Reunited and Facebook

[This comment piece on PC Pro’s website by Barry Collins](http://www.pcpro.co.uk/news/123036/comment-facebooks-not-the-new-google.html) gets some of the points about social networking spot on. In particular, it understands that **[Friends Reunited](http://www.friendsreunited.co.uk/)** — which, for a while, was one of the biggest sites in the UK — now looks like more of a dinosaur:

> Friends Reunited — once the multimillion pound poster child of the social-networking generation — is now little more than an online time capsule from 2001, with swathes of profiles that haven’t been updated in years. The site recently sponsored a TV programme on ITV (Friends Reunited’s parent company), about a woman who came out of a coma after 18 years. I’ll be amazed if Friends Reunited comes back to life that quickly.

Annoyingly, Collins doesn’t connect that situation with another nugget of information about Friends Reunited:

> I’ve yet to see any evidence that Facebook can generate significant profit from its millions of users. There’s no charge to use the site or make contact with friends — even Friends Reunited had the gumption to tap you for a fiver if you wanted to get in touch with the girl you used to ping rubber bands at in Geography lessons.

The charging structure must surely be one of the principal causes of FR’s decline. While it’s true that Facebook as yet shows no sign of having a clear, reliable and long-term revenue model (something that Collins gets spot on through his piece), ITV’s problems with Friends Reunited show that choosing the wrong revenue model can kill your site faster than any competitor ever can.

Sitting, like Buddha, in the middle

In my personal blogging, I seem to have hit a low point recently. After weeks where I’ve been busy at work, but doing nothing that was really worth talking about, I’m now in a position where I’m doing interesting stuff, but even busier, so I have even less time to talk about it even if I wanted to.

On Tuesday, the TMA kindly invited me to their day-long seminar on Online Marketing. This was because, in one of the morning sessions, Kath Moonan from [AbilityNet](http://www.abilitynet.org.uk/) was going to talk about building accessibile websites, and wanted to use [The Stage](http://www.thestage.co.uk/) as an example.

Thankfully, she was pretty complimentary about it. In an illuminating and humorous talk, she described how there was a trinity of elements that are important to a holistic view of good web accessibility:

* **Content:** Clear, easy to understand, jargon-free text.
* **Design:** Clear, high-contrast text, with all images described in their `alt` attributes, etc.
* **Markup:** Semantically structured HTML, with proper use of headings, lists, etc.

In the Venn diagram she used to illustrate how these concepts linked, Kath was kind enough to place [The Stage](http://www.thestage.co.uk/) in the intersection of all three – “sitting,” she said, “like Buddha, in the middle, contemplating the Zen-like joy of having an accessible website”. Nice.

Of course, that doesn’t mean we should rest easy. There are plenty of things that we can, and should, do better. Kath brought up some pointers that I was already aware of, and am in the process of rolling out into our revamped pages, but there were plenty that were fresh concepts to me. I hadn’t, for instance, considered whether our Hamlet cartoons should have `longdesc` descriptions of the cartoon’s plot. That’ll be one that will take a while to implement: we currently don’t have the scope to store any metadata on each cartoon. However, adding metadata –specifically, tagging each strip so that we can direct people from, say, news stories to relevant strips, and back again — is already on our future projects list, so adding additional metadata can be incorporated into the development process.

Also, I hadn’t really appreciated that low-contrast elements are less likely to affect visually impaired users (who may well use screen readers, customised style sheets or other methods to tweak websites to make them easier to use) than they are people with dyslexia or other learning difficulties. Talking to my boss, he recalled a report that suggested there was a higher level of dyslexia among the arts community than in other professions, so that’s certainly something we shall be looking at.

Luckily, we have a new web developer, James, starting next week, so I won’t be facing issues like this on my own anymore. We’ve already discussed the need to start adopting a formal testing framework, rather than the _ad hoc_ system I’ve been lucky enough to get away with to date. To be honest, that’s one reason why I find [Rails](http://www.rubyonrails.com/) so appealing, because it makes it difficult to justify _not_ formally testing everything. As we move over, I’ll be doing my best to ensure that accessibility testing can, as much as practicable, be included in all our automated tests — although, of course, automated testing is never going to be enough.

One of the areas we were pulled up on was markup on our advertising. Unfortunately, I think this is one area where we’re unlikely to be able to make much headway. The vast majority of our advertising is pulled in from third party websites — we insert a piece of supplied Javascript, which in turn generates, and inserts into the page, HTML markup that, in many cases, is woeful. Now, we may be a big fish within the UK arts community, but in the scheme of Google’s AdSense publishers (to name just one example) I suspect we’re small fry. It won’t hurt to ask, but I suspect we won’t have much luck getting stuff changed.

Eager loading objects in a Rails has_many :through association

I’m still working on the Rails application that was the source for [this tutorial](http://www.matthewman.net/articles/2006/01/06/rails-activerecord-goes-through) — which loads of developers who I really respect keep linking to, so I must have done something right there!

Anyway, I’m going to blog this bit of code in the hope that it will help me remember it.

As stated before, I have `Production` and `Venue` objects, which are linked by means of intermediary `Run` objects. Minimal code:

class Production < ActiveRecord::Base has_many :runs has_many :venues, :through => :runs
end

class Venue < ActiveRecord::Base has_many :runs has_many :productions, :through => :runs
end

class Run < ActiveRecord::Base belongs_to :production belongs_to :venue end Now, when listing the productions, I need to display a small amount of information about when and where each production is on. The rules that determine what get displayed vary, and aren't particularly relevant to the discussion here. What matters to me is that, when listing (say) 20 productions, with run and venue information included, all the data is collected in a single SQL query. As with standard joins, you can use the `find` method's `:include` option to include associated objects within the query. But I wasn't having much luck pulling in both the runs and the venues: the runs would be detected, but iterating through the productions would trigger a fresh SQL query to find the relevant venue information. Today, I found what I had to do to get it to work. The format for the find needs to be: @productions = Production.find(:all, ... , :include => {:runs => :venues})

Lo and behold, all the requisite data is collected in a single query, which substantially cuts down on the page load time on my development box.

I’m not quite sure why the hash works — or, to be honest, how I stumbled upon the solution: I’ve been scouring the internet all day, yet for some reason I can’t find the page in my browser history. All I know is that it’s not an approach I’d have stumbled upon myself, as it’s not necessarily as intuitive as most ActiveRecord code is. However, there is a certain elegance to it, with the hash’s arrow symbolising the relationship from one object type to the next, which should hopefully enable me to remember the construction in future.

How to list your audiobooks in iTunes’ Audiobooks pseudo-category

Update: With iTunes 8, moving tracks into the Audiobooks category is now trivial: Go into the track’s file information (Ctrl-I or Apple-I) and change the dropdown item on the Options tab. However, if you want to rip audiobook CDs and convert tracks to chapters, the following may still be use.

One of the reasons I distrust the new version of iTunes (see _[Why I hate iTunes 7](http://matthewman.net/2006/09/22/why-i-hate-itunes-7)_) is the utter uselessness of its new Library structure. In particular, its new Audiobooks category seems to be locked off from any books you’ve ripped yourself. Setting the Genre type of each file to “Audiobooks” isn’t enough.

Nudged by a comment from Rob, I did some digging around, and it appears that audio files will show up in the Audiobooks section if they’re bookmarkable MPEG Layer 4 files — or, in iTunes parlance, “Protected AAC files”.

On a Windows PC, it **may** be possible to get your AAC files — which should end in the extension **`.m4a`** — simply by renaming them so that the extension is **`.m4b`** (I can’t vouch for this, though, as I’m working on a Mac).

Macs are slightly trickier to deal with, anyway, as files have an internally-held file type, which must also be altered. However, I did find a couple of scripts on [Doug’s Scripts](http://www.dougscripts.com) which help.

* **[Make Bookmarkable](http://www.dougscripts.com/itunes/scripts/ss.php?sp=makebookmarkable)** converts your AAC-encoded files to their bookmarkable version, then updates their iTunes entry so that they move to the Audiobooks section.
* **[Join Together](http://www.dougscripts.com/itunes/scripts/ss.php?sp=jointogether)** allows you to combine multiple files from the iTunes Library, optionally placing chapter marks and track artwork at the appropriate sections. However, this script requires **QuickTime Pro** and Apple’s **ChapterTool** command-line utility. It can also be very slow if you don’t check the “Passthrough” option in the QuickTime settings part of the dialog.

A bonus of both scripts is that your recordings will also show up under the iPod’s own `Audiobooks` category. Bear in mind though that, unlike the standard Music folders, it doesn’t group tracks by album. So if you decide to use Make Bookmarkable, or don’t have Quicktime Pro, you could end up with lots of individual files showing up. In that case, you could consider re-importing the original audio from CD, grouping data tracks to encode as a single file.

Why I hate iTunes 7

Okay, “hate” is too strong a word — that’s the sensationalist subeditor in me, I guess. But there was something bugging me about the latest update, and I couldn’t quite put my finger on it.

I knew that it wasn’t the new, drab, grey look — it wouldn’t have been my choice, admittedly; also, it’s a shame that Apple, who impressed me when I became a Mac OSX convert with their User Interface Guidelines, do more than any other company to repeatedly flout them.

The new album view and the CoverFlow view are nice as far as they go, so it wasn’t that. I have to admit I don’t care for the restyled iTunes Music Store, and am infuriated that, in all the talk of Apple selling full-length movies to America, very few people have noticed that they’ve stopped selling even short films to us in the UK. But I only tend to use the store for a small amount of time iTunes is running, so I knew that couldn’t be what was irritating me so.

That’s when it hit me. It’s because my own library is now structured according to how Apple want to sell me stuff.

Movies and TV shows are what Apple is pushing in a big way — to American audiences, anyway. Now that short films have been lost to the ether, the only video content you can buy from the iTunes Store are music videos — and they get pushed into the generic ‘Music’ category. iTunes adds a ‘Music Videos’ smart playlist automatically, but why should it need to? It would be far better to mirror the way my iPod structures its library, with **Videos** having separate subcategories depending on the type of video content.

At least with video content that I have loaded in myself, I can change the **Video Kind** parameter of each film so that it appears in the appropriate category. However, any audiobooks that I’ve bought on CD and ripped to MP3 remain firmly stuck in “Music”. The Audiobooks category remains firmly the preserve of iTunes Store purchases, it seems — in other words, completely useless. Yes, I can switch both it and iPod Games off in iTunes’ preferences. But I’d much rather be able to add my own content to it.

It’s this twisted attitude — structuring iTunes according how they want to sell to us, rather than making it as easy to use as possible and _inspiring_ us to buy — that really pisses me off.

It’s ironic, really. The MiniStore was another way in which Apple tried to convert normal iTunes usage into a sales tool, but that’s been severely relegated in version 7. There’s no button to activate or deactivate it any more, and the shortcut key has disappeared; hopefully the whole feature will go the same way in version 8. But the philosophy behind it seems to be present still. And that, I really **do** hate.

New Rails feature: simply_helpful

UPDATE: Thanks to everybody who’s linking to this blog post, especially the mighty DHH himself. It’s worth pointing out that simply_helpful development is proceeding apace. Some of the bugs mentioned have been fixed; there are additional helpers that aren’t covered here; and, as a plugin that’s very, very new, simply_helpful may well change at short notice.

UPDATE 2: The company I work for is looking for Rails developers who are also comfy maintaining PHP code. View our job ad for more. (Done. Look forward to our first big public Rails app sometime in the summer!)

UPDATE 3: DHH linked to me again — thanks David, and welcome to all you hundreds of new visitors!

A new plugin appeared in the Rails SVN overnight, it seems. Named simply_helpful, the intention seems to be to simplify some of the most common uses of helper functions.

I suspect that these changes have been implemented as a plugin so that they don’t impinge on anybody running Edge Rails until they’re 100% stable and 100% backwards-compatible. So, if you want to explore the changes right now, you’ll have to install the plugin in your project yourself:

script/plugin install simply_helpful

With the new plugin installed, some basic helpers get simplified. For example, in my index.rhtml for my Venues controller, I used to have:

<table>
  <tr><th>Name</th> <th>City</th> <th>Postcode</th></tr>
  <%= render :partial => 'venue', :collection => @venues %>
</table>

An aside: that’s a greatly simplified version of the table; I’ve cut out a lot of stuff that would get in the way of seeing what simply_helpful is doing.

But, given that Rails can tell that my @venues array is populated with Venue instances, the new helper doesn’t need me to explicitly name the partial I’m using:

<table>
  <tr><th>Name</th> <th>City</th> <th>Postcode</th></tr>
  <%= render :partial => @venues %>
</table>

So the :collection key becomes redundant (we’re passing an Array, so a collection can be assumed), as does the naming of the partial component itself — simply_helpful automatically derives the location from the passed objects’ class — in this case, as it’s a collection of Venue objects, the partial in question is assumed to be venues/_venue.rhtml.

Along with the collection partials rendering as outlined above, you also get the following (from what my limited Ruby-brain can tell from deciphering the as-yet-undocumented code):

DOM ID attributes

<%= dom_id(object, prefix = nil) %>

Will provide an HTML ID attribute value for an onscreen object based on the object’s class and database ID. For example, dom_id(@person), where @person is a Person instance with a database ID of 123 would return person_123. If the object hasn’t been saved to the database yet, the id will be new_object_name.

By tying this feature into enhancements for RJS helpers, it means that you can now directly link DOM objects on the page to the data objects they represent. The following are now identical in meaning:

page[:person_123]
page[dom_id(@person)]
page[@person]

Pretty nifty.

DOM Class names

<%= dom_class(object) %>

Creates a CSS class name based on the object’s class — so a ProductionType object would get a DOM class of production_type.

On its own, this new function maybe isn’t as exciting as the dom_id and render improvements, but it’s used in the next feature, and it’s encouraging good practice by having clear, readable and consistent class names for your DOM objects.

Form blocks

The new form_for syntax combines with the new Restful Routes, to greatly simplify the form setup:

  • The form’s action points to an update or create action, depending on whether your object has previously been saved.
  • The form will automatically get a DOM id of new_object or edit_object_# (where object is the object’s class name, and # is its database ID), depending on whether it’s a new form or not
  • The form will also automatically get a class name of either new_object or edit_object (again, where object is your object’s class name)

This means that calls to form_for get massively simplified. For example, this line would now work for both new and existing Venue instances:

<% form_for @venue do |f| %>
...

For an existing venue object, that would produce:

<form action="http://localhost:3000/venues/123" class="edit_venue" id="edit_venue_123" method="post">
<input name="_method" type="hidden" value="put" />

whereas the same line of code would, for a new venue object, produce:

<form action="http://localhost:3000/venues" class="new_venue" id="new_venue" method="post">
<input name="_method" type="hidden" value="post" />

Unfortunately, as of right this second (revision 5050), it’s a teensy bit broken. There’s an assumption of an :html option hash being present, so I could only get it to work by changing the above line to < % form_for @venue, :html => {} do |f| %> (this is now fixed).

It also doesn’t support custom form builders yet, which I’m using in my project to automatically attach labels to fields, and to visually demarcate required fields from optional ones (I fixed this! Yay me! :-) )

But then, simply_helpful is less than a day old — these bugs will get ironed out pretty quickly. And when they do, Rails will have yet another way in which it encourages you to write simpler, better code, in a way that’s 100% backwards-compatible.

Credit where it’s due: this post by Marcel Molina Jr. helped me figure out my way round the plugin code.

Rails: ActiveRecord goes :through

Sad geek that I am, I’ve fallen a little bit in love with Ruby on Rails, the application development framework that’s ideal for building database-based web applications.

While Rails is relatively new – version 1.0 was released just last month – there are exciting things just waiting round the corner. I’m in the process of taking our existing UK theatre listings database, which currently runs with PHP and MySQL, and porting it over to Rails. In the meantime, I’ll be taking the opportunity to tidy up the database schema a bit. In doing so, I’m going to be able to take advantage of some new mechanisms only available in Edge Rails – the pre-release version of the platform.

With our database, we have two main types of object to keep track of:

* venues (e.g., the West Yorkshire Playhouse or Menier Chocolate Factory)
* productions (e.g. Phantom of the Opera, a touring production )

For productions that tour a number of venues, we construct a run sheet – a list of venues that the production will be appearing in, alongside the start and end dates of each run. Similarly, venues need a list of productions appearing at their space. In other words, both these relationships between Venue and Product objects can be represented by a Run object.

In Rails code, the three objects – and their immediate relationships with one another – are represented thus:

class Production < ActiveRecord::Base has_many :runs end class Venue < ActiveRecord::Base has_many :runs end class Run < ActiveRecord::Base belongs_to :production belongs_to :venue end So far, so good. It explains the concept in ideological terms. But what really dragged me down in PHP was managing the answers to questions that a web site visitor would have: * What's on at my favourite theatre next month? * I enjoyed this production. Where will it tour next? Maybe my friends around the country should know about it... For the real answers to human questions, we need to have a closer relationship between our Venue and Production objects. Now, in PHP – and, to an only slightly lesser extent, in Rails 1.0 – that would mean dropping down to a pure SQL level. In Rails 1.1, the `:has_many` method has a couple of new parameters that allow us to effectively bridge our intermediate object, the Run, when necessary. ### Talking it :through A basic bridging is as simple as adding a new `:has_many` method on the two main objects, adding a `:through` parameter which specifies the intermediate object. So our code now becomes: class Production < ActiveRecord::Base has_many :runs has_many :venues, :through => :runs # < = new end class Venue < ActiveRecord::Base has_many :runs has_many :productions, :through => :runs # < = new end class Run < ActiveRecord::Base belongs_to :production belongs_to :venue end (We could also add the usual extra conditions, such as an :order parameter, to determine the order in which items get retrieved -- for now, I'll leave them out to make the code as simple as possible.) Now, to get an array of all the productions that a venue has on its books, we can just say: venue.productions However, if a production plays more than once at a given venue – which has been known to happen – we'll get one copy of a Production object for each visit to a venue. If we just wanted one object per production, we can build that in to the relationship: class Venue < ActiveRecord::Base ... has_many :productions, :through => :runs,
:select => ‘DISTINCT *’
end

Behind the scenes, Rails sorts out the SQL necessary. Very impressive, when you’re used to hand-rolling it all yourself. _(Since this article was originally written, you can also add a `:uniq => true` option, which filters out duplicates after the records have been retrieved. Which method of eliminating duplicates works best for you will depend on your application.)_

But that’s not the best part.

### Association extensions

Our online database extends nearly two years back, and can only get larger. How can we answer some of the following questions?

* I’m going to be staying in Leeds sometime next Autumn. What productions might I be able to see at the West Yorkshire Playhouse?
* Where can I find the touring production of Saturday Night Fever three weeks from now?

A new feature, called association extensions, allows us to define code that only applies in the context of this relationship. Now, bear with me on this: there’s little to no documentation yet (such is the burden of working on cutting-edge technologies) and what there is doesn’t really go into detail. But this evening I had a little epiphany on how it can help me.

Let’s replace the Venue object’s relationship with its many productions, and add a little spice. (Now, this code works for me; it’s probably not the most efficient or most database-neutral. So shoot me, I’m still a learner!)

class Venue < ActiveRecord::Base ... has_many :productions, :through => :runs,
:select => ‘DISTINCT *’ do
def between(start_date = nil, end_date = nil)
date_where = []
if start_date
date_where < < %(runs.ends_on >= ‘#{start_date.strftime(“%Y-%m-%d”)}’)
end
if end_date
date_where < < %(runs.starts_on <= '#{end_date.strftime("%Y-%m-%d")}') end where_clause = date_where.join ' AND ' find :all, :conditions => where_clause
end
end
end

So now, if we want to present a quick look at all productions that are on at a given venue within a certain time frame, we can in a single line:

@venue = Venue.find_by_name(“Royal Opera House”)
@productions = @venue.productions.between(1.week.ago, 1.month.from_now)

Even better, the same `do…end` block of code could be used in the Production object to filter its Venue objects. Rails allows me to hive this off into a separate module, so both classes can share the same block of code and the same filtering techniques.

Now, you can say there are other ways to do this, and you’d be right. You can argue that stepping over the Run object like this causes problems that going a more ‘traditional’ route would avoid. You’d be right, too, in a way.

For me, though, in this particular case, the Run object is the least important of the three objects in the model. What can be thought of as “conventional” approaches give the run an undue level of priority in the scheme of things. The new features of Rails give me the opportunity to structure my model far more closely to how our customers think of our information. And that can only be a good thing.

Besides, who can’t love this line of code?

@productions = @venue.productions.between(1.week.ago, 1.month.from_now)

Hell, that’s a line of code you can show to management and they’d understand it. That’s priceless.