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

On 7 Apr 2008, at 05:35, MaddyTheGoose wrote:

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

On 7 Apr 2008, at 16:46, MaddyTheGoose wrote:

=> :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

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…

On Apr 7, 9:02 am, Frederick C. [email protected]

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

Thanks again for the help, much appreciated.

On Apr 7, 11:59 am, Frederick C. [email protected]

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs