Tom*_*Tom 7 activerecord ruby-on-rails ruby-on-rails-4
我正在尝试为我的网站上的用户Feed删除一些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
Run Code Online (Sandbox Code Playgroud)
用户模型也涉及用户具有多种具有不同属性的锦标赛和事件.为用户加载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)
Run Code Online (Sandbox Code Playgroud)
此查询尝试在急切加载锦标赛模型的"游戏"属性时检索锦标赛和赛事类型的所有FeedItem.适用于锦标赛,但在迭代FeedItems时,事件将抛出此属性不存在的错误.
我目前的hack是对每个FeedItem类型执行单独查询并将记录添加到一起.但是,这会将关联转换为我不想做的数组.
有任何想法吗?
可以为多态关联预加载嵌套关联。您需要再添加两个关联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
Run Code Online (Sandbox Code Playgroud)
之后,您可以仅预加载嵌套关联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)
Run Code Online (Sandbox Code Playgroud)
现在您无需额外查询即可获得相关锦标赛游戏:
feeds.each do |feed|
puts feed.feedable.inspect
puts feed.tournament.game.inspect if feed.feedable_type == "Tournament"
end
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
539 次 |
| 最近记录: |