Mario Zigliotto
Mario Zigliotto

Reputation: 9025

Rails Question: belongs_to with STI -- how do i do this correctly?

I've been playing around with STI and belongs_to / has_many relationships and I'm a bit confused.

I have a few questions based on a model configuration similar to:

class Parental < ActiveRecord::Base
end

class Mother < Parental
    has_many :babies
end

class Father < Parental
    has_many :babies
end

class Baby < ActiveRecord::Base
    belongs_to :?????? 
end
  1. What should Baby belong_to?
  2. In terms of a migration, what should i name/add for foreign key on the babies table?
  3. I've had a hard time researching this, is there a definitive source that explains this? The API docs did not seem to hit it on the head OR i missed it (which is totally possible).

My first thought is add parental_id to babies along with a method like Baby#owner that does the following:

Thank you!

Upvotes: 14

Views: 11020

Answers (3)

Rich Steinmetz
Rich Steinmetz

Reputation: 1301

To also get records in the other directions you'll also need to add foreign_key: 'parental_id' on the has_many relationships to do something like Mother.some_scope.preload(:babies).

class Parental < ActiveRecord::Base
end

class Mother < Parental
    has_many :babies, foreign_key: 'parental_id'
end

class Father < Parental
    has_many :babies, foreign_key: 'parental_id'
end

class Baby < ActiveRecord::Base
    belongs_to :mother, foreign_key: 'parental_id'
    belongs_to :father, foreign_key: 'parental_id'
end

And you still need belongs_to :mother, foreign_key: 'parental_id' otherwise ActiveRecord will try to build a query with WHERE babies.mother_id....

Upvotes: 0

akoller
akoller

Reputation: 79

I've solved a similar problem myself by adding an explicit foreign_key call.

Something like the following code:

class Parental < ActiveRecord::Base
end

class Mother < Parental
    has_many :babies
end

class Father < Parental
    has_many :babies
end

class Baby < ActiveRecord::Base
    belongs_to :mother, foreign_key: 'parental_id'
    belongs_to :father, foreign_key: 'parental_id'
end

Of course, this assumes that a baby has only one parent. :-)

Upvotes: 3

jefflunt
jefflunt

Reputation: 33954

The Baby belongs to both Mother and Father

belongs_to :mother
belongs_to :father

You can have multiple foreign keys. The Baby DB table then has two fields, mother_id and father_id

The definitive guide to associations is here: http://guides.rubyonrails.org/association_basics.html

The migration to create the Baby class would look something like this:

class CreateBabies < ActiveRecord::Migration
  def self.up
    create_table :babies do |t|
      t.integer :father_id
      t.integer :mother_id
    end
  end

  def self.down
    drop_table :babies
  end
end

This gives you things like: baby.mother and baby.father. You can't have a single parental_id because the foreign key can only point to one other record, meaning that babies would only have one parent (when really they have two).

Seems like, in this case, you're just misunderstanding the relationship, is all. You are on the right track.

Upvotes: 9

Related Questions