我希望我能清楚地解释清楚。
用户有很多通知和有很多电影 通知。电影has_many预告片。
通知有3列:user_id,movie_id和网站。
在预告片#index上,我正在呈现@trailers并且每个@trailer呈现 3 x ajax notification_forms(每个表单只是一个按钮,一个用于 每个"网站"选项。当用户单击此按钮时,将发送ajax请求以创建新的通知记录)
我担心的是因为我只预加载@trailers,我现在正在预告片的每次迭代中进行3次新的DB调用。
_notification_form.html.erb(每个预告片被调用3次)
<% if trailer.movie.tracked?(current_user, "netflix") %>
## do some css stuff on the button to show notification already set
movie.rb:
def tracked?(user, website)
user.notifications.where(movie_id: self.id, website: website).first
end
因此每次呈现预告片部分时,我都会进行3次DB调用。处理这种情况的正确方法是什么?
答案 0 :(得分:1)
由于您只检查current_user
的状态,并且每个Trailer
都知道其movie_id
,因此您只需加载User
&#39} Notification
并检查Trailer
s&#39; movie_id
S:
tracked = current_user.notifications
tracked.detect { |n| n.movie_id == trailer.movie_id && n.website == 'netflix' }
如果User
可能吨 Notification
,您可以将Notification
s的设置限制为Trailer
秒在您要显示的页面上:
tracked = current_user.notifications.where(movie_id: trailers.map(&:movie_id))
将其加载,然后在决定如何渲染按钮时进行检查。您可以通过创建包含Set
对的[movie_id, website]
来提高效率,这将在固定时间内进行查找。
tracked = Set.new(
current_user.nofications
.where(movie_id: trailers.map(&:movie_id))
.pluck(:movie_id, :website)
)
tracked.include?([trailer.movie_id, 'netflix'])
此策略对您来说很快,因为它完全适合您要检查的数据。如果您需要更灵活的东西,仍然可以最大限度地减少数据库查询,请考虑加入与includes
,preload
和eager_load
的关联。 3 ways to do eager loading (preloading) in Rails 3 & 4对这些方法之间的差异有很好的描述。这些都在你最初的关系加载过程中起作用(也就是说,如果你还没有加载任何东西),但是当你已经加载了部分数据时(例如,你有Trailer
但没有Movies
或Notification
s),您可以使用ActiveRecord::Associations::Preloader有效加载其余内容。