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