STI and foreign_key problem


#1

Hi,

I am trying to use STI since my classes only vary by one column in the
database.
Here is the structure (names have been changed to protect the innocent):

  Case
/       \

Registered Initial
\ /
Children

A registered case has additional information than an initial case (I
realize I could just set a flag to separate them, but there is a good
reason to separate them), but both need to be related to the children
table. Here is the model code:

class Case < ActiveRecord::Base
end

class Registered < Case
has_many :children, :foreign_key => “case_id”
end

class Initial < Case
has_many :children, :foreign_key => “case_id”
end

class Child < ActiveRecord::Base
belongs_to :initial
belongs_to :registered
end

When I attempt to access the children attribute via an Initial object I
get an unknown column exception and the dump shows the sql is trying to
select “initial_id” from the children table. This despite the fact I
specified the foreign key of ‘case_id’ in the Initial model.

This has been driving me crazy this evening. All searches for help have
come up empty. Anyone help would be greatly appreciated.

Thanks!

Peer


#2

Hi Peer,

With your structure you can add the line
has_many :children, :foreign_key => “case_id”
to the case definition.

The reason that the sql is looking for the initial_id is because the
class
Child belongs to it.

There are 3 options,

  1. Include an initial_id and a registered_id to your children table
    If there is a requirement that it belongs to an inital or registered
    case
    only include that in the validation of the child object.

  2. Include a case_id in the Child table and change the Child class
    definition to:
    class Child < ActiveRecord::Base
    belongs_to :initial, :foreign_key => ‘case_id’
    belongs_to :registered, :foreign_key => ‘case_id’
    end

I don’t know the wisdom of doing this one. Having never tried it it may
milage may be non-existant.

  1. Make Child polymorphic. Then you can associate children with
    anything.

I would tend to go for option 3. It’s cleaner and allows for the
future.


#3

Sorri to repost so soon,

Looking at your associations, you already have the case_id in the child
table.

With STI initial and registered ARE cases. So you can just use the
case_id. When you query it you can decide.

child.case.type will tell you what class it is.


#4

Peer A. wrote:

Daniel ----- wrote:

Sorri to repost so soon,

Looking at your associations, you already have the case_id in the child
table.

With STI initial and registered ARE cases. So you can just use the
case_id. When you query it you can decide.

child.case.type will tell you what class it is.

This is how I thought it was designed to work and how I thought I had
the classes configured to work just like you described here. Am I
missing something?

Peer

I figured out what I was doing wrong and I don’t think I want to mention
it in public. But since some nuby (like me) might do the same thing in
the future I guess it is only right that I do.

When I initially made the system I made separate models for Initial and
Registered then I tried to switch it to STI. I know now that I setup up
the STI correclty. However, I redeclared my classes, Initial and
Registered, in the new case.rb file and did not delete the old model
files. Parts of it were working so I thought everything was alright,
but I was still using the old models that weren’t configured properly
and hence the errors. Once I removed the old files and added the link
to the case model in application.rb everything worked just fine.
Whoops!

Thanks for listening (and helping Daniel!)

Peer


#5

Daniel ----- wrote:

Sorri to repost so soon,

Looking at your associations, you already have the case_id in the child
table.

With STI initial and registered ARE cases. So you can just use the
case_id. When you query it you can decide.

child.case.type will tell you what class it is.

This is how I thought it was designed to work and how I thought I had
the classes configured to work just like you described here. Am I
missing something?

Peer