June 19th, 2008
While working on our industrial project today, we stumbled across this situation where we need a base class (Document) that are able to refer to different type of documents (ie. Report, Screen, etc).
We found two ways of dealing with this situation, one of which is by using Single Table Inheritance (STI); and the other one we are fond of, is called Polymorphic Association.
According to [1], Single Table Inheritance is:
… an inheritance hierarchy of classes as a single table that has columns for all the fields of the various classes
We decided to go with Polymorphic Association, because we wanted different classes for different subtypes of documents. We wanted to avoid having a really large single table to store everything, and using STI might leave us with many empty fields in a row.
A little explanation of Polymorphic Association, based on my understanding. Polymorphic Association uses two fields in the base class as the foreign keys, to refer to different subclasses. It stores the ID of the subclass, and the type (model).
This is the relationship we hope to achieve:
I have created models for the above classes:
script/generate model Document
script/generate model Report
script/generate model Screen
script/generate model Process
We start by declaring the interface, and associate them:
We declare the interface in models/document.rb:
class Document < ActiveRecord::Base
belongs_to :content, :polymorphic => true
end
Then, we associate the subclasses with the interface.
In models/process.rb:
class Process < ActiveRecord::Base
has_one :document, :as => :content
end
In models/report.rb:
class Report < ActiveRecord::Base
has_one :document, :as => :content
end
In models/screen.rb:
class Screen < ActiveRecord::Base
has_one :document, :as => :content
end
Now, in Document’s migration file, create the table:
create_table :documents do |t|
t.string :title
t.string :author
t.references :content, :polymorphic => true
t.timestamps
end
In the rest of the migration files (create_report, create_screen, create_process), fill in the appropriate columns for your table, and finally run the migration.
rake db:migrate
What you will see in your database table (documents) is that Rails created two fields, namely content_id and content_type in your table. Those are the fields used to reference the subclasses.
So far, this method is able to accomplish what we had in mind.
If anyone out there have a better solution to this problem, drop me a comment. Cheers.
ref:
- P of EAA: Single Table Inheritance
Posted in Ruby on Rails | No Comments »