Polymorphic Associations & Social Channels

September 6, 2007
Posted by Pastor Zack Hubert

Note - From time to time, the Codex blog will have topics which are not likely generally interesting, but more of a Geeky nature. If it’s tagged ‘Tech Talk’, be prepared for pocket-protector pensees (in this case, skip ahead to Spider-Webs below if you just want the punchline without all the tech talk).

Last night while working on our top secret project, I ran into the following, rather interesting problem.

Background
Just like many applications, there is a place where interesting stuff is created and many places that you want that interesting stuff to go. Theoretically this is just a one to many relationship that Ruby on Rails (for instance) would describe like:


class Content < ActiveRecord::Base
has_many :consumers
end
class Consumer < ActiveRecord::Base
belongs_to :content
end

This is a pretty straightforward but unrealistic model (when does a Consumer only care about one piece of content?) but it allows you to make the following calls:

# first from the perspective of this singleminded consumer
>>zack = Consumer.find_by_name('Zack')
>>zack.content
=> returns whatever was in the source content
# or from the perspective of the content
>>code_is_fun = Content.find(:first)
>>code_is_fun.consumers
=> returns Zack and all his buddies that are interested in the same content

Polymorphism
But what is a good model if you want multiple types of content, that the consumer can indifferently consume? This is where polymorphism comes in nicely. It should be noted that the other name for Polymorphic Associations is Promiscuous Associations, but we don’t like promiscuity around here so we’ll stick with Polymorphic. We will also make it a little more realistic by allowing the consumer to be subscribed to many different channels of content.

Here’s what the model looks like (a bit more complex):

class BlogContent < ActiveRecord::Base
has_many :channels, :as => :pipeline
end
class TextContent < ActiveRecord::Base
has_many :channels, :as => :pipeline
end
class Channel < ActiveRecord::Base
belongs_to :pipeline, :polymorphic => true
has_many :subscriptions
has_many :consumers, :through => :subscriptions
end
class Subscription < ActiveRecord::Base
belongs_to :consumer
belongs_to :channel
end
class Consumer < ActiveRecord::Base
has_many :subscriptions
has_many :channels, :through => :subscriptions
end

So in this, we have a couple of content types that are exposed as a channel which the consumer can then subscribe to. Behind the scenes the Channel model has two columns which make all this happen. They are the channel_id (integer) and the channel_type (string). This allows Rails to remember which original content type to point to and which object id in that model lives in that channel. So whether it’s text or a blog or something else, the consumer can just get to it via the pipeline. What does all of this get us?

Spider-Webs
The killer thing as far as a social network is concerned is the ability to rapidly push content from the edges to the masses through self-organizing channels. When you start to draw what these networks look like, it’s a spider-web of interconnection. Why would a ‘church’ care about this?

Consider this…a small group of people learn about an elderly woman in their neighborhood who has recently taken ill. Her yard is rapidly degenerating through neglect and being Christians filled with love, they want to help her out. What if that group could easily disseminate this information to all other small groups within a 2 mile radius of that house and build an ad hoc service network.


# identify the need
>> need = NeedContent.new(:title => 'Elderly woman needs help')
>> need.save
# create a channel to communicate this need
>> channel = Channel.new(:title => 'Invite neighborhood of groups')
>> need.channels << channel
# invite other groups into this channel via subscriptions if Google says they are within the radius
>> group.subscriptions << Subscription.new(...)
# and so on...

Of course, the channel could have any kind of content…that’s the beauty of Polymorphism! Many interesting possibilities exist once you have the framework for self-organizing channels. Write in with your ideas, we’d love to hear from you.