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

On 15 Oct 2007, at 05:26, dueckes wrote:

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.

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

On Oct 15, 5:24 pm, Frederick C. [email protected]

On 16 Oct 2007, at 02:42, dueckes wrote:

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})

  1. It uses an unconventional equality check via String conversion,
    why (as per my original question)?
  2. 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