has_many children and has_many parents
-
07-09-2020 - |
Question
I'm trying to figure out a complex relation between a Model. I have a model called "Concept", which has two inheriting types called "Skill" and "Occupation". Basicly this means that each concept represents a category, but a concept can also be a skill or an occupation when going deep enough into the hierychal tree.
I'm solving this hierachy by using STI. So my schema for the Concepts table looks like this:
class CreateConcepts < ActiveRecord::Migration
def self.up
create_table :concepts do |t|
t.string :uri, :null => false, :length => 255
t.string :type, :null => true, :length => 255
t.integer :isco_code, :null => true
t.timestamps
end
end
def self.down
drop_table :concepts
end
end
The type column determins whether the Concept is a real "Concept" or a "Skill"/"Occupation". The problem now however the following relations:
EDIT:
- A Concept can belong to a single parent Concept
- An Occupation can belong to a single parent Concept
- A Skill can belong to multiple parent Concepts
- A skill has no children
- An occupation has no children
so basicly you'd have something like this:
> concept1
> concept2 concept3
> concept4 concept5 concept6 concept7 skill1
> occup1 skill2 occup2 skill5
> occup7 skill2 occup3 skill4
> occup4 skill1 occup8
I hope the picture is a bit clear what I'm trying to explain. Currently I have created the following migration to try to solve the parent-child relation but I'm not sure how to map this with the associations...
class CreateConceptLinks < ActiveRecord::Migration
def self.up
create_table :concept_links do |t|
t.integer :parent_id, :null => false
t.integer :child_id, :null => false
t.timestamps
end
end
def self.down
drop_table :concept_links
end
end
What I want to end up with is the following posssibilities:
concepta.parents => a Concept object
conceptb.children => an array of Conept objects
Occupation.parents => a Concept object
Occupation.children => []
Skill.parents => an array of Concept objects
Skill.children => []
Hope this is even possible...
Solution
You can model hierarchical relations in rails. You've got most of the way there with your migrations. Adding the relations below should allow you to do the method calls you'd like:
def Concept < ActiveRecord::Base
has_many :child_links, :class_name => 'ConceptLink', :foreign_key => 'parent_id'
has_many :children, :through => :child_links
has_many :parent_links, :class_name => 'ConceptLink', :foreign_key => 'child_id'
has_many :parents, :through => :parent_links
end
def ConceptLink < ActiveRecord::Base
belongs_to :child, :class_name => "Concept"
belongs_to :parent, :class_name => "Concept"
end
I'd also take a look at this blog posting which does a very good of explaining parent-child mappings in rails.