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 }