why is this rails association loading individually after an eager load?

Posted by codeman73 on Stack Overflow See other posts from Stack Overflow or by codeman73
Published on 2010-01-21T16:40:46Z Indexed on 2010/04/28 17:03 UTC
Read the original article Hit count: 299

I'm trying to avoid the N+1 queries problem with eager loading, but it's not working. The associated models are still being loaded individually.

Here are the relevant ActiveRecords and their relationships:

class Player < ActiveRecord::Base
  has_one :tableau
end

Class Tableau < ActiveRecord::Base
  belongs_to :player
  has_many :tableau_cards
  has_many :deck_cards, :through => :tableau_cards
end

Class TableauCard < ActiveRecord::Base
  belongs_to :tableau
  belongs_to :deck_card, :include => :card
end

class DeckCard < ActiveRecord::Base
  belongs_to :card
  has_many :tableaus, :through => :tableau_cards
end

class Card < ActiveRecord::Base
  has_many :deck_cards
end

and the query I'm using is inside this method of Player:

def tableau_contains(card_id)
  self.tableau.tableau_cards = TableauCard.find :all, :include => [ {:deck_card => (:card)}], :conditions => ['tableau_cards.tableau_id = ?', self.tableau.id]
  contains = false
  for tableau_card in self.tableau.tableau_cards
    # my logic here, looking at attributes of the Card model, with        
    # tableau_card.deck_card.card;
    # individual loads of related Card models related to tableau_card are done here
  end
  return contains
end

Does it have to do with scope? This tableau_contains method is down a few method calls in a larger loop, where I originally tried doing the eager loading because there are several places where these same objects are looped through and examined. Then I eventually tried the code as it is above, with the load just before the loop, and I'm still seeing the individual SELECT queries for Card inside the tableau_cards loop in the log. I can see the eager-loading query with the IN clause just before the tableau_cards loop as well.

EDIT: additional info below with the larger, outer loop

Here's the larger loop. It is inside an observer on after_save

def after_save(pa)
  @game = Game.find(turn.game_id, :include => :goals)
  @game.players = Player.find :all, :include => [ {:tableau => (:tableau_cards)}, :player_goals ], :conditions => ['players.game_id =?', @game.id]
  for player in @game.players
    player.tableau.tableau_cards = TableauCard.find :all, :include => [ {:deck_card => (:card)}], :conditions => ['tableau_cards.tableau_id = ?', player.tableau.id] 
    if(player.tableau_contains(card))
    ...
    end
  end
end

© Stack Overflow or respective owner

Related posts about ruby-on-rails

Related posts about activerecord