Archive for June, 2006

Polymorphic Association in Rails

Thursday, June 15th, 2006

Here is an account of my first use of Rails 1.1’s polymorphism in Model associations.

I had looked at all the examples at the wiki and a couple of other blogs but still wasn’t clear.

You appreciate most, the problems that you solve yourselves :-)

Here is the problem I solved using Polymorphic associations.

Consider the scenario where there are Users of an application; who can act as both buyers and providers. Each user can infact have multiple buyer and provider profiles.
The application also has a messaging system for users to contact each other.
As a part of the application requirement, we need to keep track of the profiles of the message sender and receiver.

A user logs in using the login name and password present in the User model. I am omitting details so please assume for this example that each logged in user, has either a buyer profile or a provider profile associated to it, when they use the messaging system.

Here are the model files

A user can have many buyer_profiles and many provider_profiles


class User < ActiveRecord::Base
  has_many :buyer_profiles
  has_many :provider_profiles
end

A buyer profile belongs to a user and can have many messages associated to it as a sender and as a receiver.


class BuyerProfile < ActiveRecord::Base
  belongs_to :user
  has_many :messages, :as => :sender
  has_many :messages, :as => :receiver
end

A provider profile also belongs to a user, and can have many messages associated to it as a sender and as a receiver.


class ProviderProfile < ActiveRecord::Base
  belongs_to :user
  has_many :messages, :as => :sender
  has_many :messages, :as => :receiver
end

The message model holds the polymorphic magic, via the two interfaces sender and receiver. A message belongs to sender which can be polymorphic,either a buyer or a provider. And also a message belongs to a receiver, which again is polymorphic, either a provider or a buyer.


class Message < ActiveRecord::Base
  belongs_to :sender, :polymorphic => true
  belongs_to :receiver, :polymorphic => true
end

The code above requires that I have these four special fields in my messages table to handle polymorphism. Here is the migration for messages


class CreateMessagesTable < ActiveRecord::Migration
  def self.up
    create_table :messages do |t|
      t.column :sender_id, :integer
      t.column :sender_type, :string
      t.column :receiver_id, :integer
      t.column :receiver_type, :string
      t.column :subject, :string
      t.column :message, :string
    end
  end

  def self.down
    drop_table :messages
  end
end

I ran the following code on the console to check if everything is working as expected.


r = BuyerProfile.find(1)
s = ProviderProfile.find(1)
m = Message.new
m.sender = s
m.receiver = r
m.subject = "test subject"
m.message = "test message"
m.save!

And it worked :-)

I could access profles and users from the message object like this.


m = Message.find(1)
m.receiver                 # refer to the receivers profile object
m.receiver.class          # get receiver type, where BuyerProfile or SellerProfile
m.sender                   # refers to the sender profile object
m.sender.class            # get sender type, where BuyerProfile or SellerProfile
m.receiver.user           # refer the User object of the message receiver
m.sender.user             # refer the User object of the message sender

Polymorphism saved me a lot of time and also a whole new table which I was thinking of adding to handle this functionality prior to polymorphism.

Added : And yes, now I am thinking about what I would need to write to get all the messages sent or received by a User.

RJS templates for Rails

Wednesday, June 14th, 2006

Cody Fauser, the guy who created RJS templates for Rails, has written a book “RJS templates for Rails”.

It is available as a pdf download from oreilly for only US$9.99.

I was recently reading the code for ajax scaffold plugin, which uses a lot of RJS. This book should help me get a better understanding of it.