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.