Question about Associations and Eager Loading

Hey everyone,

I’m currently making an application that allows users to create custom
fields that have attributes associated with each field.

They can then attach instances of these fields (each with their own
separate attribute instances) to their account.

So, it looks like this:

     Fields
 /             \

Field Instances Field Attributes
\ /
Field Attribute Instances

Where Field Instances and Field Attributes both belong to Field, and
have
many Field Attribute Instances. So the kicker here is that Field
Attribute Instances are dependent on both Field Instances and Field
Attributes.

I need to get an array that looks like the following:
Fields.FieldInstances.FieldAttributes.FieldAttributeInstances

Right now, I’m doing something like the following:
Field.find(:all, :include => { :field_instances => { :field_attributes
=>
{ :field_attribute_instances } } }) which gives me the order I want.
However, I see no way to get field_attribute_instances dependent on
BOTH
field_attributes and field_instances (instead of just field_attributes,
as
it currently is)

In fact, even if I specify that in the :conditions option, Active Record
will ignore it and add any and all field_attribute_instances that are
dependent on field_attribute (even if they don’t match field_instances).

If the order in which I include things changes to FieldInstances =>
FieldAttributeInstances => FieldAttribute then I get the results I need,
but not the array I need.

Any suggestions on how I can go about fixing this problem?

Thanks.

Field.find(:all, :include => { :field_instances =>
{ :field_attributes =>
{ :field_attribute_instances } } })

This looks right to me. Have you tried adding a compound condition:
:conditions => [‘field_instances.id = ? AND field_attributes.id =?,
3, 4’]

        - dan


Dan K. mailto:[email protected]
http://www.dankohn.com/ tel:+1-415-233-1000

Field.find(:all, :include => { :field_instances =>
{ :field_attributes =>
{ :field_attribute_instances } } })

This looks right to me. Have you tried adding a compound condition:
:conditions => [‘field_instances.id = ? AND field_attributes.id =?,
3, 4’]

        - dan

Hi Dan,

Yes, I’ve tried that (actually, not exactly that, but :conditions =>
‘field_attribute_instances_field_attributes.field_instance_id =
field_instances.id’, as well as a bit of a hack - :joins => ‘AND
field_attribute_instances_field_attributes.field_instance_id =
field_instances.id’)

Running the query in my MySQL client gives me the correct results (ie.
field_attribute_instances are dependent on both field_attributes and
field_instances).

However, it seems that Active Record is interpreting the :includes
option
a bit too literally for my needs, basically doing something like
(pseudocode):

if field_attribute_instances.field_attribute_id == field_attributes.id
Field.FieldInstance.FieldAttribute << field_attribute_instances
end

(where the condition should be:
field_attribute_instances.field_attribute_id == field_attributes.id &&
field_attribute_instances.field_instance_id == field_instances.id)

Thanks again for the help

  • Marcel

Sorry, I meant includes overriding selects. It could be overriding
conditions too.

        - dan


Dan K. mailto:[email protected]
http://www.dankohn.com/ tel:+1-415-233-1000

I find I can usually work this out by working with script/console and
watching development.log to see what SQL ActiveRecord is generating.
There’s at least one open bug regarding the includes overriding the
conditions. If you can confirm that that is happening here too, you
should file a bug report.

In the meantime, I don’t understand why you would need to bother
with the joins, as AR passes conditions right through (after
sanitizing the variables).

http://dev.rubyonrails.org/ticket/5371

        - dan


Dan K. mailto:[email protected]
http://www.dankohn.com/ tel:+1-415-233-1000

I would:

  1. Post the bug to dev.rubyonrails.com, attaching your two test
    files. I can’t see how you can argue it’s a feature.

  2. Simply use a find_by_sql call to get exactly the functionality you
    want.

         - dan
    


Dan K. mailto:[email protected]
http://www.dankohn.com/ tel:+1-415-233-1000

Sorry, I meant includes overriding selects. It could be overriding
conditions too.

        - dan


Dan K. mailto:[email protected]
http://www.dankohn.com/ tel:+1-415-233-1000

Hey Dan,

Thanks again for your help. I’m wondering though, if it’s a bug or
expected behaviour. I’ve narrowed the code down to a (fairly) simple
testcase and posted it on http://www.marcelguzman.com/rails/ (the
migration generates 6 rows of simple test data, and the output from
console shows the bug).

Any idea if I’d be able to get around that or not?

If I switch the order of includes to :field_instances =>
:field_attribute_instances => :field_attributes , then it grabs
everything
perfectly, but then I’m stuck becasue I need to access the data in the
following order:
field_instances => field_attributes => field_attribute_instances

I suppose I could try using something like an ORDER BY clause and then
looping through, catching when field_attribute_id changes. But that
does
seem incredibly hacky to me and I’m wondering if there’s a better way.

Thanks again,
Marcel

http://www.dankohn.com/ tel:+1-415-233-1000
Hi Dan, thanks again for your help - you’ve been of great assistance :slight_smile:

  1. I will definitely do that tonight, but I want to prepare some more
    detailed test data first to make the bug more evident.

  2. I could do that - but is there any way to use find_by_sql such that
    it
    will still allow me to use the association collections, or will I have
    to
    manually process the returned data?

Thanks,
Marcel