Active Record associations wiredness.

Hi all,

    Can anyone explain why line 1372 of lib/active_record/
associations.rb performs a String equality check as opposed to a more
conventional Object equality check:

return nil if record.id.to_s != join.parent.record_id(row).to_s or
row[join.aliased_primary_key].nil?

I stumbled across this when attempting to monkey patch the Oracle
Adapter as I noticed that on some occasions columns were incorrectly
interpreted as Floats instead of Integer.

Any answers much appreciated.

Kind Regards,

Matthew Ueckerman

Because of the thing where ids are sometimes integers (eg User.find 123) and sometimes strings.

Fred

Thanks for the response Fred.

Perhaps some more context would help. Executing the following
triggers this code:

Customer.find(1, :include => :orders)

The include clause adds a join to the resulting SQL so that the
Customer and it's related Orders can be retrieved via a single query.
This code comes into play after the query executes and acts on the
result set; it appears to be verifying the child (Order) has a
matching foreign key to the parent (Customer) in the result set.

So here's my original question with some points/Q's thrown in:
1. The verification appears to be redundant as the query contains a
where clause limiting the result set to the parent id.
2. It uses an unconventional equality check via String conversion,
why (as per my original question)?
3. Invoking record.id causes adapter specific logic to execute that
may convert the type of the value to some other type, however
join.parent.record_id(row) does not perform that same logic - I
suspect this is a defect? As a consequence of this I've seen cases
where 1 != 1.0 (for instance)

Again, any help much appreciated.

Regards,

Matthew

Thanks for the response Fred.

Perhaps some more context would help. Executing the following
triggers this code:

Customer.find(1, :include => :orders)

The include clause adds a join to the resulting SQL so that the
Customer and it's related Orders can be retrieved via a single query.
This code comes into play after the query executes and acts on the
result set; it appears to be verifying the child (Order) has a
matching foreign key to the parent (Customer) in the result set.

So here's my original question with some points/Q's thrown in:
1. The verification appears to be redundant as the query contains a
where clause limiting the result set to the parent id.

In your case yes: there is only one parent, but not in the case when you've got Customer.find(1,2,3, :include => :orders) or Customer.find(1, :include => {:orders => :products})

2. It uses an unconventional equality check via String conversion,
why (as per my original question)?
3. Invoking record.id causes adapter specific logic to execute that
may convert the type of the value to some other type, however
join.parent.record_id(row) does not perform that same logic - I
suspect this is a defect? As a consequence of this I've seen cases
where 1 != 1.0 (for instance)

The main thing is to avoid instatiating more AR objects than are needed, the way :include works more rows are returned than there are objects emerging on the other end, eg if the customer has 10 orders, you don't want to instatiate the customer 10 times. I expect 2. is an attempt to make this work most of the time without the adapter specific logic from record.id.

The short answer is that :include is usually quite overcomplicated (as someone who also once read through the JoinBase / JoinDependency code you have my sympathy). There is a simple solution in the pipeline, but it's not quite ready yet.

Fred