2013-10-21 79 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 –