logo{ :from => Delhi, :about => everything }


Polymorphic Association in Rails

Posted in ruby on rails, rails by manik on the 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.

Tags: , ,

RJS templates for Rails

Posted in ruby on rails, books by manik on the 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.

Tags: ,