Help: odd results from many-to-many self-referential relationship with attribute in join table

I'm having an issue with the data returning from a self-referential many-to-many relationship with an attribute in the join table that's being used to limit the query. I'll explain what I'm doing below which will then bring you to the problem concerning the records I'm getting back from the relationship.

MIGRATIONS (the two tables involved in the problem)

Note that in contained_gear_items there are three items related to gic[1] and list_id 1 and two other items related to gic[1] but belong to list_id 2 so I would think I wouldn't see them (considering I have 'contained_gear_items.list_id" => 1' in the conditions - see below). When looking at .contained_items the list_id = 1 constraint seems to have been missed. But if I go directly into the contained_gear_items join model I see only the three items, as I should. Any help would be much appreciated.

so, data wise, contained_gear_item goes like this:

id gear_item_id contained_gear_item_id list_id 1 4 9 2 2 4 10 2 5 4 5 1 6 4 6 1 7 4 7 1

#011_create_contained_gear_items.rb (migration) class CreateContainedGearItems < ActiveRecord::Migration   def self.up     create_table :contained_gear_items do |t|       t.integer "gear_item_id", :null => false       t.integer "contained_gear_item_id", :null => false       t.integer "list_id", :null => false       t.integer "position"       t.timestamps     end   end

## 001_create_gear_items.rb (migration) class CreateGearItems < ActiveRecord::Migration   def self.up     create_table :gear_items do |t|       t.string "title", :limit => 100, :null => false       t.boolean "is_container", :default => false       t.timestamps     end   end

MODELS

## gear_item.rb (model) class GearItem < ActiveRecord::Base   has_many :contained_gear_items   has_many :contained_items, :through => :contained_gear_items

## contained_gear_item.rb (model) class ContainedGearItem < ActiveRecord::Base   belongs_to :gear_item   belongs_to :contained_item, :class_name => 'GearItem',     :foreign_key => 'contained_gear_item_id'

IN THE SCRIPT/CONSOLE

gic = GearItem.find(

  :all,   :include => "contained_gear_items",   :conditions => {"contained_gear_items.list_id" => 1, :is_container => true},   :order => "contained_gear_items.position")

puts gic[1].contained_items

#<GearItem:0x3efeb80> #<GearItem:0x3efeb30> #<GearItem:0x3efeae0> #<GearItem:0x3efea90> #<GearItem:0x3efea40>

puts gic[1].contained_gear_items

#<ContainedGearItem:0x3f2c56c> #<ContainedGearItem:0x3f29a4c> #<ContainedGearItem:0x3f27328>

Thanks for any help you can provide...

Cheers

I'm having an issue with the data returning from a self-referential many-to-many relationship with an attribute in the join table that's being used to limit the query. I'll explain what I'm doing below which will then bring you to the problem concerning the records I'm getting back from the relationship.

Your problem is only with the eager loading: when you load the has
many through it does not use the already loaded contained_items to get
the association, and so the conditions you specified at that point do
not apply. You probably want to specify the conditions on the
association itself, although I'm not entirely sure what you're trying
to do.

Fred

First off, thanks for the help.

I did try adding the condition to the association itself but it didn't seem like the right place for it although I could be wrong (I am pretty new to rails). I had it like this:

class GearItem < ActiveRecord::Base   has_many :contained_gear_items   has_many :contained_items, :through => :contained_gear_items, :conditions => "contained_gear_items.list_id = 1"

which works as I wanted but shouldn't the associations only deal with the relationship but not so much with conditions (leaving the conditions to the find)? I guess I'm looking for some best-practices here. I want to be able to dynamically change the list_id. I may be looking at this wrong and perhaps have to change the way I think if the above is the right way to do it.

Is there a way to move the condition above into the find?

Essentially what I'm trying to achieve is: A GearItem can contained 0..n GearItems and the GearItem->GearItem relationship belongs to a list. So list 1 can have GearItem 1 containing GearItem 2 & 3 but list 2 can have GearItem 2 containing GearItem 1 & 4, etc...

First off, thanks for the help.

I did try adding the condition to the association itself but it didn't seem like the right place for it although I could be wrong (I am pretty new to rails). I had it like this:

class GearItem < ActiveRecord::Base has_many :contained_gear_items has_many :contained_items, :through => :contained_gear_items, :conditions => "contained_gear_items.list_id = 1"

which works as I wanted but shouldn't the associations only deal with the relationship but not so much with conditions (leaving the conditions to the find)?

Not necessarily, it can definitely be used to good effect (eg customer
has_many :orders and customer
has_many :outstanding_orders, :conditions => '...')

I guess I'm looking for some best-practices here. I want to be able to dynamically change the list_id. I may be looking at this wrong and perhaps have to change the way I think if the above is the right way to do it.

Is there a way to move the condition above into the find?

Essentially what I'm trying to achieve is: A GearItem can contained 0..n GearItems and the GearItem->GearItem relationship belongs to a list. So list 1 can have GearItem 1 containing GearItem 2 & 3 but list 2 can have GearItem 2 containing GearItem 1 & 4, etc...

In this case having all the conditions in the association probably
isn't the right thing to do since you'd have to have one association
per list and you'd have to figure out what to call them

You could do this via an association proxy, eg

has_many :contained_items, :through => :contained_gear_items do    def from_list(n)      find :all, :conditions => ["contained_gear_items.list_id = ?", n]    end end

Then you can do stuff like foo.contained_items.from_list(23)

Fred

Love it. Just implemented it and it looks good so far...

Thanks again for the help, much appreciated.