Take the diagram below. A release can have many test cases in it, but it could also have bugs which need to be checked in the same release. Now we could create a join table between releases and cases as well as releases and bugs, or we could just use one join table that can link releases to both cases and bugs.
OK, time to install the plugin:
Installing using script/plugin install proved a problem, so you can also do this
Goto Github and download the plugin.
http://github.com/fauna/has_many_polymorphs/tree/master
You can then untar it, and move it to the folder
vendor/plugins/has_many_polymorphs
Now lets generate our models.
Keep an eye on the Releaseable model. It has only three columns
release_id - the release that the other models map to
runable_id - holds the id of the model that is joining to it
runable_type - holds the model name.
Using runable_id and runable_type, we know the model to look for, as well as the id of that model.
class Release < ActiveRecord::Base
has_many_polymorphs :runables, :from=>[:cases, :bugs], :through=>:releaseables
end
class Releaseable < ActiveRecord::Base
belongs_to :release
belongs_to :runable, :polymorphic=>true
end
class CreateFun < ActiveRecord::Migration
def self.up
create_table :releases do |t|
t.string :version
end
create_table :cases do |t|
t.string :title
t.text :steps
t.text :expected
end
create_table :bugs do |t|
t.string :title
t.text :description
end
create_table :releaseables do |t|
t.integer :release_id
t.integer :runable_id
t.string :runable_type # very important that this is a string!
end
end
def self.down
drop_table :releases
drop_table :cases
drop_table :bugs
drop_table :releasables
end
end
And that is it for a poylmorphic relationship. No methods need to be put in the Case or Bug models. So we can add as many relationships to releases by only editing the Release model.
Now lets use our new models. First we'll create our release, bug and case.
Release.create(:version=>1)
Bug.create(:title=>'Bug 1')
Case.create(:title=>'Case 1')
Case.create(:title=>'Case 2')
Joining them is as easy as using '<<'
Release.bugs << Bug.find(1)
Release.cases << Case.find(1)
If we look at our database now, we case see our runable_id, along with our runable_type so we know which table to look up to retrieve our record
+----+------------+------------+--------------+
| id | release_id | runable_id | runable_type |
+----+------------+------------+--------------+
| 1 | 1 | 1 | Bug |
| 2 | 1 | 1 | Case |
+----+------------+------------+--------------+
If we want to see what cases and bugs we have on a release, we can use
Release.find(:first).runable
to see all the bugs and cases.
Or, we can find the bugs or cases on their own
Release.find(1).bugs
Release.find(1).case
There is one other way to associate a case with a release, we can create a Releaseable record directly. This is really useful if we also want to set some extra attributes on the join table(Releaseable).
Releaseable.create(:release=> Release.find(:first), :runable=>Case.find(2))
Its as simple as that!
No comments:
Post a Comment