2015-12-09 30 views
1

我希望我能清楚地解釋這一點。Rails:通過控制器中的關係預加載has_many

  • 用戶has_many通知和has_many電影通過 通知。電影has_many預告片。

  • 通知有3列:user_id,movie_id和網站。

  • 在拖車#指數,我渲染@trailers每個@trailer呈現 3×AJAX notification_forms(每份表格只是一個按鈕,一個 每個「網站」選項,當用戶點擊這個按鈕, AJAX請求被髮送到創建一個新的通知記錄)

  • 我跟蹤哪些按鈕被按下(通過查找,看是否通知存在該用戶/電影)

我擔心的是,因爲我只是預加載@trailers,我目前正在每個預告片的迭代中創建3個新的數據庫調用。

_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數據庫調用。處理這種情況的正確方法是什麼?

回答

1

因爲你只檢查current_user的狀態和每個Trailer知道它movie_id,你可以加載UserNotification S和檢查他們爲Trailer S'movie_id S:

tracked = current_user.notifications 
tracked.detect { |n| n.movie_id == trailer.movie_id && n.website == 'netflix' } 

如果User可能有Notification S,你可以限制Trailer S中的頁面上設置爲僅Notification是你正在顯示:

tracked = current_user.notifications.where(movie_id: trailers.map(&:movie_id)) 

加載它,然後在決定如何渲染按鈕時進行檢查。您可以通過創建一個包含[movie_id, website]對的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,preloadeager_load的熱切加載關聯。 3 ways to do eager loading (preloading) in Rails 3 & 4對這些方法之間的差異有很好的描述。這些都在你的初始關係加載期間工作(也就是說,如果你還沒有加載任何東西),但是當你已經加載了部分數據(例如,你有Trailer s,但不是Movies s或Notification s),您可以使用ActiveRecord::Associations::Preloader高效地加載其餘部分。

+0

謝謝!太棒了 –

相關問題