Forum: Ruby on Rails Single Table Inheritance

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Alex Y. (Guest)
on 2005-12-29 16:36
(Received via mailing list)
Hi all,

Quick question for STI.  With the following setup:

class Company < AR::Base; end
class Firm < Company; end

Why does Firm.find(:all) return all Companies, not just those that have
type=='Firm'?
Reginald Braithwaite (Guest)
on 2005-12-29 18:53
(Received via mailing list)
On 12/29/05, Alex Y. <removed_email_address@domain.invalid> wrote:
> Hi all,
>
> Quick question for STI.  With the following setup:
>
> class Company < AR::Base; end
> class Firm < Company; end
>
> Why does Firm.find(:all) return all Companies, not just those that have
> type=='Firm'?

That sounds like a good feature. My naive question would be this: what
happens if you define:

class BigFirm < Firm; end

Does Firm:find :all return instances of BigFirm as well, or just
instances of Firm?

--
Reginald Braithwaite
http://www.braithwaite-lee.com/weblog/

Like all text messages, email exchanged with a gmail account may be
stored indefinitely and/or read by third parties without the sender or
receiver's knowledge or permission. Please do not send any privileged
or confidential transmission to this account: enquire about secure
alternatives.

Experience and Treachery will beat Youth and Talent every time.
Alex Y. (Guest)
on 2005-12-29 19:02
(Received via mailing list)
Reginald Braithwaite wrote:
> That sounds like a good feature. My naive question would be this: what
> happens if you define:
>
> class BigFirm < Firm; end
>
> Does Firm:find :all return instances of BigFirm as well, or just
> instances of Firm?
Logically, it should...  All BigFirms are Firms, after all.
Wilson B. (Guest)
on 2005-12-29 19:11
(Received via mailing list)
On 12/29/05, Alex Y. <removed_email_address@domain.invalid> wrote:
> Hi all,
>
> Quick question for STI.  With the following setup:
>
> class Company < AR::Base; end
> class Firm < Company; end
>
> Why does Firm.find(:all) return all Companies, not just those that have
> type=='Firm'?
>

Having Firm.find(:all) return only entries with type=='Firm' would
mean that there would be some 'implicit' conditions attached.
My wild guess as to why this isn't done is that it could get very
tricky to add that into an arbitrary set of conditions.
Firm.find(:all, :conditions => "blah = 1 and thingy = 'y' ")
..AR would need to add "and type = 'Firm'" to the end of the conditions.
Now what happens when you're doing a more complex condition, possibly
involving group by, having, 'partition over', etc.. knowing where to
inject a 'where' could be sticky.

That being said, it would be a cool feature.  At the moment,
Company.find_all_by_type('Firm')  is probably the shortest answer.
Alex Y. (Guest)
on 2005-12-29 19:42
(Received via mailing list)
Wilson B. wrote:
> Having Firm.find(:all) return only entries with type=='Firm' would
> mean that there would be some 'implicit' conditions attached.
> My wild guess as to why this isn't done is that it could get very
> tricky to add that into an arbitrary set of conditions.
> Firm.find(:all, :conditions => "blah = 1 and thingy = 'y' ")
> ..AR would need to add "and type = 'Firm'" to the end of the conditions.
> Now what happens when you're doing a more complex condition, possibly
> involving group by, having, 'partition over', etc.. knowing where to
> inject a 'where' could be sticky.
True, but the with_scope method already does something similar.  In
fact, looking through the find() method, it looks like it should be
doing it anyway, with the construct_finder_sql() method...  Maybe I
messed something else up...
Reginald Braithwaite (Guest)
on 2005-12-29 20:12
(Received via mailing list)
On 12/29/05, Alex Y. <removed_email_address@domain.invalid> wrote:
> Reginald Braithwaite wrote:
> > That sounds like a good feature. My naive question would be this: what
> > happens if you define:
> >
> > class BigFirm < Firm; end
> >
> > Does Firm:find :all return instances of BigFirm as well, or just
> > instances of Firm?
> Logically, it should...  All BigFirms are Firms, after all.
>

That makes things interesting. find_all_by_type('Firm') doesn't work
for this case (nor does implicitly adding WHERE type='Firm').

One approach would be to walk the class tree at run time, then
construct WHERE (type = 'Firm' OR type = 'BigFirm' or...). In Ruby,
that's a challenge because there might be a class that hasn't been
seen by the interpreter yet, but there is a row of that type.

The obverse approach would be to scan the table (ugh). You could
SELECT DISTINCT Company.type and test each type against firm using
#kind_of? to get a lits of sub-types.

This kind of thing could certainly be done. But if you don't feel like
hacking ActiveRecord, you can probably roll your own domain-specific
solution using a mixin.

--
Reginald Braithwaite
http://www.braithwaite-lee.com/weblog/

Did you know... The longest word in the English language, according to
the Oxford English Dictionary, is
"pneumonoultramicroscopicsilicovolcanoconiosis".
Scott W. (Guest)
on 2005-12-29 20:21
(Received via mailing list)
You're right, it should use SQL like: SELECT * FROM firms WHERE
(firms.`type` = 'Firm' ). I have seen class loading order cause
inconsistent behavior with STI queries, though the effect is the
opposite of your problem.

For instance, if I also have MultiNationalFirm < Firm, and I run
Firm.find_all, I will get Companies, Firms, but not
MultiNationalFirms. If I then reference MultiNationalFirm and do the
run Firm.find_all again, I will get Companies, Firms, _and_
MultiNationalFirms.

BTW, you have "Company < AR::Base" in your example. I assume you just
abbreviated "ActiveRecord::Base?"

Scott
Alex Y. (Guest)
on 2005-12-29 20:30
(Received via mailing list)
Scott W. wrote:
> You're right, it should use SQL like: SELECT * FROM firms WHERE
> (firms.`type` = 'Firm' ). I have seen class loading order cause
> inconsistent behavior with STI queries, though the effect is the
> opposite of your problem.
>
> For instance, if I also have MultiNationalFirm < Firm, and I run
> Firm.find_all, I will get Companies, Firms, but not  MultiNationalFirms.
> If I then reference MultiNationalFirm and do the  run Firm.find_all
> again, I will get Companies, Firms, _and_  MultiNationalFirms.
>
That's just...  odd.  Presumably in an SCGI environment that would then
be non-deterministic?

> BTW, you have "Company < AR::Base" in your example. I assume you just
> abbreviated "ActiveRecord::Base?"
That's right.  I nicked those examples from the ActiveRecord docs
because they're a little more intuitive than what I'm actually using,
which are CSVInsert, LabelledInsert and TestimonialInsert.  Don't ask
:-)
Scott W. (Guest)
on 2005-12-29 21:00
(Received via mailing list)
On Dec 29, 2005, at 10:11 AM, Reginald Braithwaite wrote:
>  In Ruby,
> that's a challenge because there might be a class that hasn't been
> seen by the interpreter yet, but there is a row of that type.

Right, that's the root cause. In my apps, I've been able to
effectively work around this by explicitly referencing all my STI
classes at start-up (it's a FXRuby app, not web-based). So, in my
init script, I say something like:
MultiNationalFirm
Firm
Company

On Dec 29, 2005, at 10:19 AM, Alex Y. wrote:
> That's just...  odd.  Presumably in an SCGI environment that would
> then be non-deterministic?

Not sure. I wouldn't be surprised if you see the same behavior there,
though.

> Wilson B. wrote:
>> My wild guess as to why this isn't done is that it could get very
>> tricky to add that into an arbitrary set of conditions.
>> Firm.find(:all, :conditions => "blah = 1 and thingy = 'y' ")
>> ..AR would need to add "and type = 'Firm'" to the end of the
>> conditions.
>> Now what happens when you're doing a more complex condition, possibly
>> involving group by, having, 'partition over', etc.. knowing where to
>> inject a 'where' could be sticky.
>>

I think you are right, too. When you get to this point, you're at the
boundaries of what the ActiveRecord class/pattern can do for you, and
it's time to use explicit SQL.

Scitt
This topic is locked and can not be replied to.