Welcome to Giant Robots Smashing Into Other Giant Robots — a weblog about development, business, design and technology — written by thoughtbot.
for the record
Ok, I just want to set this one in stone.
Rails’ polymorphic associations.
Ask yourself 2 questions:-
Can this object belong to more than 1 type of object
Here’s a domain model from an app in which you can purchase both cars and houses. They are both salable products that will appear on a line item in an order. This is a many-to-1 relationship from a1 2 3 4 5 6 7 8 9 10 11
class Car < ActiveRecord::Base end class House < ActiveRecord::Base end class LineItem < ActiveRecord::Base belongs_to :salable, :polymorphic => true end
LineItemto its salable product. -
Can this object belong to more than 1 type of object and more than 1 object
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
class User < ActiveRecord::Base include Groupable end class Account < ActiveRecord::Base include Groupable end class Membership < ActiveRecord::Base belongs_to :groupable, :polymorphic => true belongs_to :group end class Group < ActiveRecord::Base has_many :memberships end module Groupable def self.included(clazz) clazz.class_eval has_many :memberships, :as => :groupable end end end
Here we have a many-to-many between groupable objects and groups. Since a
Groupcan contain members of different types it needs to be polymorphic. However, in this example a single group can have multiple members all of different types. Like any many-to-many we need a table between the 2 other tables. Since habtm doesn’t support polymorphic associations we have to go with a join model. So we introducedMembershipand made it have a polymorphic relationship.It’d be sweet if we didnt need this join model because I can’t stand unnecessary classes, something like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
class User < ActiveRecord::Base include Groupable end class Account < ActiveRecord::Base include Groupable end class Group < ActiveRecord::Base has_and_belongs_to_many :groupables end module Groupable def self.included(clazz) clazz.class_eval has_and_belongs_to_many :groups, :as => :groupable end end end
db schema:
groupables (groupable_id, groupable_type, group_id)
That’s some made up syntax. I’ll say if you have an:asparameter to #has_and_belongs_to_many then Rails will look for a table named after the polymorphic interface, in this casegroupables, and 2 columnsgroupable_idandgroupable_type. Since the #has_and_belongs_to_many call in theGroupmodel doesn’t include an:asparameter, Rails will, like in a normal #has_and_belongs_to_many call, look for a table named after the association, in this casegroupables, and a foreign key in that table referencing this model, in this casegroup_id.
About this entry
You're reading an entry on GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS, the company weblog of thoughtbot, inc.
- Author:
- Jared Carroll
- Published:
- September 12th 10:22 AM
- Updated:
- September 30th 09:57 AM
- Sections:
- Development
thoughtbot is hiring
We are hiring web developers and web designers in both Boston and New York, NY.
What are we up to?
We built Shoulda, an eclectic set of additions to Test::Unit; Paperclip to manage uploaded files without hassle; Jester, a REST/ActiveResource client library written in Javascript, and Squirrel, an enhancement for ActiveRecord's find syntax; — amongst some other projects.

Chad (President) and Jon (CTO) co-authored a technical book titled Pro Active Record: Databases with Ruby and Rails, which explores the ins and outs of the ActiveRecord ruby library. You can buy it today at Amazon.com.
About thoughtbot, inc.
We are a small web application development consulting business, with offices in Boston, MA and New York, NY. If you're looking to find a team for your next web development project or your new web application — get in touch.
1 comment
Jump to comment form