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.