0

有像我如何有效地更新在軌相關聯的集合(預先加載)

class Slot < ActiveRecord::Base 
    has_many :media_items, dependent: :destroy 
end 

class MediaItem < ActiveRecord::Base 
    belongs_to :slot 
end 

MediaItems一個簡單關聯每Slot是有序的,有一個叫ordering場。 並想避免n + 1查詢但我沒有嘗試過。我讀了一些相關博客文章,railscasts等,但嗯..他們從來沒有在一個單一的模式運作等等...

我要做的就是:

def update 
    @slot = Slot.find(params.require(:id)) 

    media_items = @slot.media_items 
    par = params[:ordering_media] 
    # TODO: IMP remove n+1 query 
    par.each do |item| 
    item_id = item[:media_item_id] 
    item_order = item[:ordering] 
    media_items.find(item_id).update(ordering: item_order) 
    end 
    @slot.save 
end 

params[:ordering_media]是一個JSON陣列media_item_id和爲ordering 整我嘗試之類的東西

@slot = Slot.includes(:media_items).find(params.require(:id)) # still n+1 
@slot = Slot.find(params.require(:id)).includes(:media_items) # not working at all b/c is a Slot already 
media_items = @slot.media_items.to_a # looks good but then in the array of MediaItems it is difficult to retrieve the right instance in my loop 

這似乎是一個常見的事,所以我認爲這是一個簡單的方法來解決這個問題。瞭解它會很好。

+0

您更喜歡哪種方式:在插槽表單上爲每個媒體項目填寫訂單字段,或將媒體項目拖放到插槽展示上? – 2014-10-23 11:50:38

回答

1

首先,在這一行media_items.find(item_id).update(ordering: item_order)你沒有n + 1問題,你有一個2 * n問題。因爲對於每個media_item,您可以進行2個查詢:一個用於查找,另一個用於更新。要解決,你可以這樣做:

params[:ordering_media].each do |item| 
    MediaItem.update_all({ordering: item[:ordering]}, {id: item[:media_item_id]}) 
end 

這裏有n查詢。這是我們可以做的最好的事情,沒有辦法用n個不同的值更新n條記錄上的列,並且少於n條查詢。

現在您可以刪除行@slot = Slot.find(params.require(:id))@slot.save,因爲@slot未在更新操作中修改或使用。

有了這個重構,我們看到一個問題:動作SlotsController#update根本不更新插槽。此代碼的更好位置可能是MediaItemsController#sortSortMediaItemsController#update(更多RESTful)。

在最後@slot = Slot.includes(:media_items).find(params.require(:id))這不是n + 1查詢,這是2 SQL語句查詢,因爲你檢索n media_items和1槽只有2 db調用。這也是最好的選擇。

我希望它有幫助。

+0

非常有幫助和很好的解釋。我不得不使用下面的語法* update_all *'''MediaItem.where(id:item [:media_item_id])。update_all(ordering:item [:ordering])'''我可以在控制檯看到*加載*語句丟失。你對重構的看法是有道理的,但現在唯一與mediaItems交互的方法就是通過插槽。這只是一個API,沒有渲染頁面/表單。 – einSelbst 2014-10-27 09:46:26