views:

201

answers:

1

Hey all,

I'm trying to use the scriptaculous helper method sortable_element to implement a drag-and-drop sortable list in my Rails application. While the code for the view looks pretty simple, I'm really not quite sure what to write in the controller to update the "position" column.

Here's what I've got in my view, "_show_related_pgs.erb":

<ul id = "interest_<%=@related_interest.id.to_s%>_siblings_list">
    <%= render :partial => "/interests/peer_group_map", :collection => @maps, :as => :related_pg %>
</ul>

<%= sortable_element("interest_"+@related_interest.id.to_s+"_siblings_list", :url => {:action => :resort_related_pgs}, :handle => "drag" ) %>
<br/>

And here's the relevant line from the partial, "interests/peer_group_map.erb"

  <li class = "interest_<%=@related_interest.id.to_s%>_siblings_list"
         id = "interest_<%=related_pg.interest_id.to_s%>_siblings_list_<%=related_pg.id.to_s%>">

The Scriptaculous UI magic works fine with these, but I am unsure as to how to change the "position" column in the db to reflect this. Should I be passing the collection @maps back to the controller and tell it to iterate through that and increment/decrement the attribute "position" in each? If so, how can I tell which item was moved up, and which down? I couldn't find anything specific using Chrome dev-tools in the generated html.

After each reordering, I also need to re-render the collection @maps since the position is being printed out next to the name of each interest (I'm using it as the "handle" specified in my call to sortable_element() above) - though this should be trivial.

Any thoughts?

Thanks, -e

A: 

I typically create a sort action in my controller that looks like this:

def sort
  order = params[:my_ordered_set]
  MyModel.order(order)
  render :nothing => true
end

Don't forget to add a route:

map.resources :my_model, :collection => { :sort => :put }

Now, on MyModel I add a class method that updates all of the sorted records with one query (this only works in mysql, I think..):

def self.order(ids)
  update_all(
    ['ordinal = FIND_IN_SET(id, ?)', ids.join(',')],
    { :id => ids }
  )
end

The single query method comes from Henrik Nyh.

Jimmy Baker
Thanks - I found a railscast that explained this, which I modified a bit (gave params a string instead of :this_thing, so as to keep variable div names). But this "update all at once" thing looks really fast/useful/cool, thanks!
Eli B.