How to create a sortable interface with 'acts as nested set' in RubyOnRails
Asked Answered
B

5

6

I've been implementing some nice interactive interfaces that can sort lists in my m rails app for models that use acts_as_list. I have a sort function that gets called and sets the position for each record afterr each drag and drop using the sortable_element script.aculo.us function.

This is an example of the controller action that handles the sort after the drag and drop completes:

  def sort
    params[:documents].each_with_index do |id, index|
      Document.update_all(['position=?', index+1], ['id=?', id])
    end
  end

Now I am trying to do this same thing with a model that is a nested set (acts_as_nested_set). An example of the type of interface interaction: http://script.aculo.us/playground/test/functional/sortable_tree_test.html

I am stuck on how to write the controller action to handle the sort when the drag and drop completes.

I've added the :tree=>true parameter to the sortable _element function so far which appears to send a list of hashes but it seems that I am still missing information about the entire nested order....

I was certain this has been done before and didn't want to try to reinvent the wheel, but I can't seem to find any examples of the controller action <-> view with js function setup to handle a sortable acts_as_nested_set

Any help with creating an interactive sortable nested set in rubyonrails would be appreciated!

Thanks,

John

Bimetallism answered 5/5, 2009 at 14:0 Comment(3)
Using the awesome nested set plugin in case anyone is interested in helping... it basically extends the original nested _setBimetallism
Are there built-in ways to match the order passed from params hash to the entire nested set of all of the items in the model?Bimetallism
I need exactly the same thing built with jQuery. Up voted you anyways.Rothschild
A
2

see example app here - http://github.com/matenia/jQuery-Awesome-Nested-Set-Drag-and-Drop

It's a hacky way of doing it, but its basically, sort first, then save order. Uses nestedsortables, serializelist, and 2 actions to traverse the tree

PS: I know this question is over a year old but hoping that the link above helps someone else coming here.

edit: added Rails3 example with some slightly cleaner code.

Avera answered 5/9, 2010 at 1:1 Comment(0)
P
2

a good solution with ONE sql-query from http://henrik.nyh.se/2008/11/rails-jquery-sortables

# in your model:

def self.order(ids)
  update_all(
    ['ordinal = FIND_IN_SET(id, ?)', ids.join(',')],
    { :id => ids }
  )
end
Plutocrat answered 1/11, 2010 at 14:41 Comment(1)
I think this only work for lists, not nested sets. On the other hand, it's a MySQL only solution.Cathexis
L
1

Just found this:

sortable_element_for_nested_set on github

Looks like it'll do the job, however I'm having some bugs while trying to implement it. It basically makes the javascript return the id of the element that was moved, then goes through the elements and returns its new parent, left and right values. Can't believe it's taken this long for something like this to be written! Lucky it was just when I needed it :)

Louisville answered 25/5, 2009 at 23:49 Comment(0)
D
1

Here's a snippet of code from my project that does the trick:

http://gist.github.com/659532

 def reorder_children(ordered_ids)
    ordered_ids = ordered_ids.map(&:to_i)
    current_ids = children.map(&:id)
    unless current_ids - ordered_ids == [] && ordered_ids - current_ids == []
      raise ArgumentError, "Not ordering the same ids that I have as children. My children: #{current_ids.join(", ")}. Your list: #{ordered_ids.join(", ")}. Difference: #{(current_ids - ordered_ids).join(', ')} / #{(ordered_ids - current_ids).join(', ')}" 
    end
    j = 0
    transaction do
      for new_id in ordered_ids
        old_id = current_ids[j]
        if new_id == old_id
          j += 1
        else
          Category.find(new_id).move_to_left_of(old_id)
          current_ids.delete(new_id)
        end
      end
    end
  end

You call it on the parent, and it'll sort the children.

You just pass in the value that you get from Sortable, like so:

  def reorder
    @category.reorder_children(params[:categories])
    render :nothing => true
  end

Hope this helps.

//Lars

Dramaturge answered 2/11, 2010 at 11:58 Comment(0)
U
0

the_sortable_tree

Sortable Nested Set for Rails 3.1+

Dreaming about Drag and Drop for Nested Sets? It’s should be with JQuery? Here’s the solution!

Unplumbed answered 23/8, 2011 at 13:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.