rails процесс сохранения порядка awesome_nested_set с использованием jquery & nestedsortables

У меня есть модель категорий с фантастическим набором awesome_nested. Я успешно сгенерировал дерево перетаскивания и успешно сгенерировал полный хэш этого дерева с помощью плагина SERIALIZELIST и отправил его в метод "array", который я добавил в свой контроллер категорий. (используя jquery и nestedsortables) Хеш из моего журнала выглядит так...

Обработка массива CategoriesController# (для 127.0.0.1 в 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

Я надеюсь, что это достаточно информации, и надеюсь, что кто-то может ответить на этот вопрос.

Ура,

Matenia

----------- ОБНОВЛЕНИЕ И ПРОГРЕСС -----------

С тех пор, как я опубликовал это несколько дней назад, я просмотрел 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 различных категорий. Это не лучший способ, но он работает.

Ура снова,

Matenia


ЗАКЛЮЧИТЕЛЬНОЕ РЕШЕНИЕ

У меня была проблема с приведенным выше кодом, когда он не спасал детей должным образом. Вот моя последняя попытка, которая, кажется, работает хорошо.

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 DRAG AND DROP + SERIALIZELIST PLUGIN ....

Ура,

Matenia

2 ответа

Решение

См. отредактированный вопрос выше для окончательного решения.. Я разместил код на github.. хотя он может иметь несколько ошибок и нуждается в рефакторинге ПЛОХО! JQUERY NESTED SORTABLES - DRAG AND DROP - УДИВИТЕЛЬНЫЙ ВСТРОЕННЫЙ КОМПЛЕКТ

ОБНОВЛЕНИЕ: добавлен пример рельсов 3 для репо с немного более чистым кодом

Та же проблема возникла при обновлении приложения 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 }
Другие вопросы по тегам