IS A - What's polymorph

May 4th, 2008

Polymorph is useful because it allows you treat objects of different types uniformly.

NOTE: There is a plugin that saves you from writing the following code, and it also adds extra functionality. See the tutorial has_many_polymorphs for dummies

This article contains some code and irb tests I did when learning about polymorph from these articles.

An Article_Section is made up of various types of content.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20


class ArticleSection < ActiveRecord::Base
  belongs_to :article

  has_many :article_contents
#   This code is better than that below and it works
#   has_many :notes,    :through => :article_contents, :source => :contentizable,
#                       :source_type => 'Note'
  has_many :notes,    :through => :article_contents, :source => :note,
                      :conditions => "article_contents.contentizable_type = 'Note'"
  has_many :links,    :through => :article_contents, :source => :link,
                      :conditions => "article_contents.contentizable_type = 'Link'"

  def contentizables
  self.notes + self.links
 end

end

Content can be placed in many articles.
Content can be of various type i.e. text, code, url's

1
2
3
4
5
6
7
8
9
10
11
12

class ArticleContent < ActiveRecord::Base

   belongs_to :article_sections
   belongs_to :contentizable, :polymorphic => true
   #  This code is better than that below and works.
   #  has_many :notes, :as => :contentizable
   belongs_to :note,  :class_name => "Note",
                         :foreign_key => "contentizable_id"
   belongs_to :link,     :class_name => "Link",
                         :foreign_key => "contentizable_id"
end

Note Object is of type Content

1
2
3
4
5

class Note < ActiveRecord::Base
  has_many :article_contents, :as => :contentizable
  has_many :article_sections, :through => :article_contents
end

Link object is of type Content

1
2
3
4
5

class Link < ActiveRecord::Base
  has_many :article_contents, :as => :contentizable
  has_many :article_sections, :through => :article_contents
end

Testing using the irb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

>> a = Article.create(:title => "a1")
=> #<Article id: 12, title: "a1", published_at: nil, author: nil, keywords: nil, state: nil, created_at: "2008-05-01 18:07:41", updated_at: "2008-05-01 18:07:41">
>> as = ArticleSection.create(:article_id => a.id )
=> #<ArticleSection id: 11, article_id: 12, content_id: nil, content_type: nil, order: nil, created_at: "2008-05-01 18:07:44", updated_at: "2008-05-01 18:07:44">
>> as.notes
=> []
>> as.links
=> []
>> l = Link.create(:url => "some.domain.com")
=> #<Link id: 3, content_id: nil, url: "some.domain.com", description: nil, title: nil, contentizable_id: nil, contentizable_type: nil, created_at: "2008-05-01 18:08:20", updated_at: "2008-05-01 18:08:20">
>> as.links << l
=> [#<Link id: 3, content_id: nil, url: "some.domain.com", description: nil, title: nil, contentizable_id: nil, contentizable_type: nil, created_at: "2008-05-01 18:08:20", updated_at: "2008-05-01 18:08:20">]
>> n = Note.create(:description => "hi", :title => "something")
=> #<Note id: 9, description: "hi", contentizable_id: nil, contentizable_type: nil, created_at: "2008-05-01 18:08:41", updated_at: "2008-05-01 18:08:41", title: "something", content_id: nil>
>> as.notes << n
=> [#<Note id: 9, description: "hi", contentizable_id: nil, contentizable_type: nil, created_at: "2008-05-01 18:08:41", updated_at: "2008-05-01 18:08:41", title: "something", content_id: nil>]
>> as.article_contents
=> [#<ArticleContent id: 1, article_section_id: 11, contentizable_id: 3, contentizable_type: nil, created_at: "2008-05-01 18:08:25", updated_at: "2008-05-01 18:08:25">, #<ArticleContent id: 2, article_section_id: 11, contentizable_id: 9, contentizable_type: nil, created_at: "2008-05-01 18:08:49", updated_at: "2008-05-01 18:08:49">]
>> as.article_contents.length
=> 2

Another test using the irb

1
2
3
4
5
6
7

>> n = Note.create(:title => "t", :description => "d")
=> #<Note id: 14, description: "d", contentizable_id: nil, contentizable_type: nil, created_at: "2008-05-01 19:08:46", updated_at: "2008-05-01 19:08:46", title: "t", content_id: nil>
>> as.notes << n
=> [#<Note id: 12, description: "d", contentizable_id: nil, contentizable_type: nil, created_at: "2008-05-01 19:07:51", updated_at: "2008-05-01 19:07:51", title: "t", content_id: nil>, #<Note id: 13, description: "d", contentizable_id: nil, contentizable_type: nil, created_at: "2008-05-01 19:08:06", updated_at: "2008-05-01 19:08:06", title: "t", content_id: nil>, #<Note id: 14, description: "d", contentizable_id: nil, contentizable_type: nil, created_at: "2008-05-01 19:08:46", updated_at: "2008-05-01 19:08:46", title: "t", content_id: nil>]
>> n.article_contents
=> [#<ArticleContent id: 6, article_section_id: 21, contentizable_id: 14, contentizable_type: "Note", created_at: "2008-05-01 19:08:50", updated_at: "2008-05-01 19:08:50">]

Leave a Reply