0

我有一个用很棒的 awesome_nested 集制作的类别模型。我已经成功地生成了拖放树,并使用 SERIALIZELIST 插件成功地生成了该树的完整哈希,并将其发送到我添加到类别控制器中的“数组”方法。(使用jquery和nestedsortables)我的日志中的哈希看起来像这样......

处理 CategoriesController#array (for 127.0.0.1 at 2010-08-19 23:12:18) [POST] 参数:{"ul"=>{"0"=>{"class"=>"", "id" =>"category_1", "children"=>{"0"=>{"class"=>"", "id"=>"category_4", "children"=>{"0"=>{"class" =>"", "id"=>"category_3"}}}}}, "1"=>​​{"class"=>"", "id"=>"category_2", "children"=>{"0 "=>{"class"=>"", "id"=>"category_5"}, "1"=>​​{"class"=>"", "id"=>"category_6"}}}}}

我只是在使用排序功能时遇到了麻烦。

很棒的嵌套集确实提供了一些移动功能,但我似乎无法理解它。

当用户点击保存时,我想做这样的事情(顺便说一句,它执行 ajax 请求并正确传递上述数据)

def array
    newlist = params[:ul]
    newlist.each_with_index do |id, index, children|
      #insert code here for saving the re-ordered array
    end
    render :nothing => true
end

我希望这是足够的信息,并希望有人可以回答这个问题。

干杯,

马特尼亚

------------ 更新和进展 ------------

自从几天前发布此内容以来,我在我的开发环境中使用 logger.info 来查看幕后发生的事情。

我最终写了2个函数。一个遍历数组的根,另一个递归地将孩子和孩子的孩子移动到位。但这最终会导致太多的数据库调用(尽管可能没有其他方法可以做到)。

代码看起来像这样......

  def array
    # fetch the current tree
    @allcategories = Category.all
    # assign the sorted tree to a variable
    newlist = params[:ul]
    # initialize the previous item
    previous = nil
    #loop through each item in the new list (passed via ajax)
    newlist.each_with_index do |array, index|
      # get the category id of the item being moved
      moved_item_id = array[1][:id].split(/category_/)
      # find the object that is being moved (in database)
      @current_category = Category.find_by_id(moved_item_id)
      # if this is the first item being moved, move it to the root.
      unless previous.nil?
        @previous_item = Category.find_by_id(previous)
        @current_category.move_to_right_of(@previous_item)
      else
        @current_category.move_to_root
      end
      # then, if this item has children we need to loop through them
      unless array[1][:children].blank?
        # unless there are no children in the array, send it to the recursive children function
        childstuff(array[1], @current_category)
      end
      # set previous to the last moved item, for the next round
      previous = moved_item_id
    end
    render :nothing => true
  end
  def childstuff(node, category)
    # find the category that has been passed into the function
    @selected_category = Category.find(category)
    for child in node[:children]
      child_id = child[1][:id].split(/category_/)
      child_category = Category.find_by_id(child_id)
      child_category.move_to_child_of(@selected_category)
      #if this child has children -- run recursion on this function
      unless child[1][:children].blank?
        childstuff(child[1], child_category)
      end
    end
  end

我希望有人可以阐明如何提高效率以及如何减少数据库调用的数量。我曾考虑过编写其他函数,但它们都会做同样的事情。

对于这个特定的项目,我不相信会有超过 100 个不同的类别。这不是最好的方法,但它确实有效。

再次欢呼,

马特尼亚


最后的解决方法

我对上面的代码有一个问题,它没有正确地保存孩子。这是我最近的尝试,似乎效果很好。

def array
    # assign the sorted tree to a variable
    newlist = params[:ul]
    # initialize the previous item
    previous = nil
    #loop through each item in the new list (passed via ajax)
    newlist.each_with_index do |array, index|
      # get the category id of the item being moved
      moved_item_id = array[1][:id].split(/category_/)
      # find the object that is being moved (in database)
      @current_category = Category.find_by_id(moved_item_id)
      # if this is the first item being moved, move it to the root.
      unless previous.nil?
        @previous_item = Category.find_by_id(previous)
        @current_category.move_to_right_of(@previous_item)
      else
        @current_category.move_to_root
      end
      # then, if this item has children we need to loop through them
      unless array[1][:children].blank?
        # NOTE: unless there are no children in the array, send it to the recursive children function
        childstuff(array[1], @current_category)
      end
      # set previous to the last moved item, for the next round
      previous = moved_item_id
    end
    Category.rebuild!
    render :nothing => true
  end
  def childstuff(mynode, category)
   # logger.info "node = #{node} caegory = #{category}"
    #loop through it's children
    for child in mynode[:children]
      # get the child id from each child passed into the node (the array)
      child_id = child[1][:id].split(/category_/)
      #find the matching category in the database
      child_category = Category.find_by_id(child_id)
      #move the child to the selected category
      child_category.move_to_child_of(category)
      # loop through the children if any
      unless child[1][:children].blank?
        # if there are children - run them through the same process
        childstuff(child[1], child_category)
      end
    end
  end

仍然有太多的数据库调用,但我想这是想要这个功能所要付出的代价,因为它需要重新记录数据库中的每个项目。

希望这可以帮助其他有需要的人。如果有人需要这方面的帮助,请随时给我发信息。

真棒嵌套集 + JQUERY 拖放 + SERIALIZELIST 插件....

干杯,

马特尼亚

4

2 回答 2

3

有关最终解决方法,请参见上面编辑过的问题 ..我已在 github 上发布了代码 .. 虽然它可能有一些错误并且需要严重重构! JQUERY 嵌套排序 - 拖放 - 真棒嵌套集

更新:添加了 rails 3 示例以使用更简洁的代码进行回购

于 2010-11-05T14:01:07.480 回答
0

将 rails 2.3 应用程序升级到 3.1 时出现了同样的问题。就我而言,我只想排序一个深度(根与否)。这就是我最终得到的结果:

# Fetch all IDs (they will be in order)
ids = params[:sort].collect { |param| param[/^page_(\d+)$/, 1] }
# Remove first item from array, moving it to left of first sibling
prev = Page.find(ids.shift)
prev.move_to_left_of(prev.siblings.first)
# Iterate over remaining IDs, moving to the right of previous item
ids.each_with_index { |id, position| current = Page.find(id); current.move_to_right_of(prev); prev = current }
于 2011-11-15T10:54:07.397 回答