2013-10-21 33 views
7

Sitemde kullanıcı besleme için bazı N + 1 sorgularını kaldırmaya çalışıyorum. Bir FeedItem modeliKoşullu olarak istekli yükleme polimorfik dernekler

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 

Bir kullanıcı modeli de dahil olduğu bir polimorfik ilişki var çeşitli modelleri vardır nerede bir kullanıcı has_many Turnuvalar ve her iki farklı özelliklere sahip Olaylar. Bir kullanıcı için FeedItems'i yüklerken, koşullu olarak hangi FeedItem türüne bağlı olarak iç içe öznitelik yüklerim?

I (squeel DSL ile birlikte) ne anlama geldiğini bir örnek:

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) 

Bu sorgu Turnuva modelin 'oyun' özelliğini yüklenirken istekli iken tipi Tournament'a Olay tüm FeedItems almaya çalışır. Turnuvalar için iyi çalışır, ancak FeedItems'i tekrarlarken olaylar bu özelliğin bulunmadığı bir hatayı atar.

Geçerli kesmek, her FeedItem türü için ayrı ayrı sorgular yapmak ve kayıtları birlikte eklemektir. Ancak bu, ilişkilendirmeyi yapmak istemediğim bir diziye dönüştürür.

Herhangi bir fikrin var mı?

+0

Hala ayrı sorgularınızı yapabilir, ancak herhangi bir şey yüklemek yerine her birinden FeedItem kimliklerini ekleyebilirsiniz. Topladığınız tüm kimliklerin bir dizisini oluşturun ve bunu istekli olduğunuz tek sorgunuza aktarın. – Humza

cevap

1

Polymorphic dernekleri için iç içe geçmiş ilişkilendirmeleri önceden yüklemek mümkündür. Yalnızca tournament için iç içe geçmiş bir ilişki önyükleyebilir

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 

Bundan sonra:

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) 

Şimdi ilgili alabilirsiniz turnuva oyun ek sorgu olmadan:

feeds.each do |feed| 
    puts feed.feedable.inspect 
    puts feed.tournament.game.inspect if feed.feedable_type == "Tournament" 
end 
Sen FeedItem için iki dernek eklemem gerekiyor
+0

Bu sürüm Rails 4.2'de çalışır –