[英]Rails: preloading a has_many through relation in the controller
我希望我能清楚地解釋這一點。
用戶通過通知has_many通知和has_many電影。 電影有很多預告片。
通知包含3列:user_id,movie_id和網站。
在trailers#index上,我正在渲染@trailers,每個@trailer都渲染3個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調用。 處理這種情況的正確方法是什么?
由於您只檢查current_user
的狀態,並且每個Trailer
知道它的movie_id
,因此您只需加載User
的Notification
並檢查它們的Trailer
的movie_id
:
tracked = current_user.notifications
tracked.detect { |n| n.movie_id == trailer.movie_id && n.website == 'netflix' }
如果一個User
可能有一噸的Notification
S,你可以限制設置為僅Notification
S為Trailer
你顯示在頁面上S:
tracked = current_user.notifications.where(movie_id: trailers.map(&:movie_id))
加載它,然后在決定如何呈現按鈕時僅對其進行檢查。 您可以通過創建包含[movie_id, website]
對的Set
提高效率,該Set
將在固定時間內進行查找。
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
渴望加載的關聯。 Rails 3和4中3種進行緊急加載(預加載)的方法很好地描述了這些方法之間的差異。 這些都在初始關系加載期間(即,如果您還沒有加載任何東西)工作,但是當您已經加載了部分數據時(例如,您擁有Trailer
但沒有Movies
或Notification
),您可以使用ActiveRecord :: Associations :: Preloader有效地加載其余部分。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.