2013-10-21 42 views
7

我试图消除一些N + 1查询的用户饲料在我的网站上。有迹象表明,有一个多态关联到FeedItem模型有条件地渴望加载多态关联

class Event < ActiveRecord::Base 
    has_many :feed_items, as: :feedable 
end 

class Tournament < ActiveRecord::Base 
    has_many :feed_items, as: :feedable 
end 

class FeedItem < ActiveRecord::Base 
    belongs_to :feedable, :polymorphic => true 
end 

也参与用户模型各种型号,其中用户的has_many赛事和活动这两个具有不同的属性。当为用户加载FeedItems时,我如何有条件地加载基于哪个FeedItem类型的嵌套属性?

我的意思(与squeel DSL)的一个例子:

FeedItem.where{ (feedable_id.in(@user.tournaments.ids}) & feedable_type.eq('Tournament')) |  
       (feedable_id.in(@user.events.ids) & feedable_type.eq('Event')) }.includes(:feedable => :game) 

这个查询试图检索类型比赛和事件的所有FeedItems而急于加载锦标赛模型的“游戏”的属性。适用于锦标赛,但在迭代FeedItems时,事件会抛出此属性不存在的错误。

我目前的做法是为每个FeedItem类型分别查询并将这些记录添加到一起。然而,这将关联转换为一个我不想做的数组。

任何想法?

+0

你仍然可以做你的单独查询,但从每个查询FeedItem标识,而不是加载任何东西。创建一个您收集的所有ID的数组,并将其传递到您渴望加载的单个查询中。 – Humza

回答

1

可以为多态关联预加载嵌套关联。你需要两个协会加入FeedItem

class FeedItem < ActiveRecord::Base 
    belongs_to :feedable, :polymorphic => true 

    belongs_to :event, -> { where(feedable_type: 'Event') }, foreign_key: :feedable_id 
    belongs_to :tournament, -> { where(feedable_type: 'Tournament') }, foreign_key: :feedable_id 
end 

之后,你只能为tournament预装嵌套协会:

feeds = 
    FeedItem.where(" 
    (feedable_id IN (?) AND feedable_type = 'Tournament') OR 
    (feedable_id IN (?) AND feedable_type = 'Event')", @user.tournament_ids, @user.event_ids). 
    includes(:feedable, tournament: :game) 

现在,你可能会得到相关的比赛游戏,无需额外的查询:

feeds.each do |feed| 
    puts feed.feedable.inspect 
    puts feed.tournament.game.inspect if feed.feedable_type == "Tournament" 
end 
+0

该版本适用于Rails 4.2 –