Don't forget to mention that the SQL indexes on the 'position' column MUST NOT be unique, because of the temporary duplicates created by the progressive updates in the sort action.
an idea for next weeks rails cast. expand upon this using categories. in an application i have now, i have my faqs linked to a specific category. my users can order the categories themselves in addition to the group of faqs under each category.
How hard would it be to extend this to nested lists, using acts_as_tree? In particular, dragging a sublist item to another sublist, or making it a parent (out-denting)?
Hi Ryan,
I am happy with your railscast video but i can't download source code.
When I tried to download source code of all episodes i got source code upto episode no.136 only.
Please check it out of there is any prob. in git.
If any of you out there are trying to use Ryan's technique to sort <tr> elements inside a table, make sure you
(1) read the documentation for Sortable.create, especially the important information under "Notes" (see http://wiki.github.com/madrobby/scriptaculous/sortable-create), and
(2) pass :tag => "tr" to your call to the sortable_element helper method.
Ironically...the most valuable thing I got out of this was "each_by_index", haha! Found myself using a separate indexer "i" a number of times, had no idea this existed! Thanks Ryan.
Thanks for the example! I needed to do something like this today, and while I could have put it together myself from the pieces, your example is a complete picture of how I wanted to implement it, even down to the collection RESTful action :) And to think I stumbled across it through pure luck from Google, even before iTunes had downloaded today's video from the podcast.
Thanks for the episode. I've learned a ton from you and am very thankful. If I can vote for a future episode topic, I'd like to see something about using an asset service like Amazon S3 with Rails. I have some upcoming projects that want to do heavy video streaming and have been thinking about using something like S3 for the application. Thanks!
But in my app, each user will have the power to sort the list in his own way.
I'm trying a "rich join table" with (user_id, item_id, position) to relate a item to a user and to know it's position in relation to this specific user.
But I keep getting errors. I know this insn't very clear... But if someone can help me how to do something like that, I would be thankful!
Tutorials like these, the ones that focus on the "basics" are crucial to making our community standout from other web frameworks.
All average rails devs should be able to whip off a sortable draggable list in minutes. This screencast makes a nice dent in the right direction. I know there is voting out on UserVoice, but I would strongly encourage you to consider extending a few additional ajax centric screencasts similar to this to move our cumulative ball further down the field.
Perhaps centering on a few of the other scriptaculous modules such as expandable-collapsible divs, inline editing, ajax tabs, sliders, etc.
Essentially a toolbox of the common UI patterns we are commonly asked to provide our clients but are not always entirely obvious to implement.
@Mario, content_tag_for accepts a model as an argument, and it will give the tag attributes based on the model's name and id.
@pulkit, weird. Do you still have this problem? Perhaps GitHub was having difficulties.
@Jcooper, great question! If you just float the list elements to the left it should work. You'll also want to set the
":constraint => false" option on sortable_element so the item can be dragged horizontally as well.
@R Sturim, thanks, I'll definitely consider working on some more basic ajax screencasts in the near future.
@Shreyans, Rails is doing some magic here, it parses the name of the migration and knows we're trying to add the position column to the faqs table. This was added in Rails 2.0, see the episode on that for details.
http://railscasts.com/episodes/83-migrations-in-rails-2-0
Sorted it (no pun intended, really). I had to do the for each on the association model in the middle. It looks like there are a few more db accesses to get anything from the models I really want though as each call to the associated model on the other side must get loaded afterwards.
Do you know how to use this to sort by more than just position? I want to sort people with drag/drop, but maintain two columns, male and female. Can u sort by, say, position and sex?
Great tip !! Thanks.
However, I think that the sort action
could be made to be more efficient. If I understood right, it generates a separate update for each line, every time the user drags a faq. Better to generate a single update string and execute it after the loop (in the sort action).
Can this technique be combined with the dynamic list that you presented in #73? I would like to be able to add elements and sort them during creation and edit.
For a jQuery-based alternative that works on trees instead of flat lists, see http://blog.ronaldevers.nl/posts/6-rails-sortable-element-helper-with-jquery
Here's something I found on making a sorted, nested list:
http://www.justinball.com/2009/01/18/heirarchies-trees-jquery-prototype-scriptaculous-and-acts_as_nested_set/
via
http://stackoverflow.com/questions/198047
It uses
http://github.com/collectiveidea/awesome_nested_set
but it seems sorta complicated. Got any simpler solutions?
Wow, coming up to 3 years old and this is still a super easy way of doing sorting by dragging. I have just used this approach alongside your brilliant nested attributes tutorials (http://railscasts.com/episodes/196-nested-model-form-part-1) and it works just as well as the simple model example you use in this tutorial.
For me I have a Page model with nested attributes on a Snippet model (all very CMS based). If anyone was thinking of doing the same, go for it. I did this - it may help you:
1 - added a controller for the nested model - "Snippet" in my case (not needed otherwise) which just contains the "sort" method as you have it i.e.
ruby
classSnippetsController < ApplicationControllerdefsort
params[:snippets].each_with_index do |id, index|
Snippet.update_all(["position=?", index+1], ["id=?", id])
end
render :nothing => trueendend
2 - add the drag n drop code to my show view rather than my index view like this:
erb
<ul id="snippets">
<% for snippet in @page.snippets %>
<%= content_tag_for :li, snippet do %>
<span class="handle">[drag]</span>
<%= snippet.body %>
<% end %>
<% end %>
</ul>
<%= sortable_element("snippets", :url => sort_snippets_path, :handle => "handle") %>
it helped me to keep the sorting feature out of the way of the nested attribute feature in the edit view for my parent model
3 - since i am Rails 3.0.x based i have added a default_order scope to my nested model to handle the sorting bit:
ruby
classSnippet < ActiveRecord::Base
belongs_to :page
acts_as_list
scope :default_order, order("position")
end
4 - for Rails 3 i have also used the routing approach added by Tyler Gannon in these comments i.e.
ruby
resources :snippetsdo
collection do
post :sortendend
all works a treat. thank you for your excellent work as always Ryan!
glenn
p.s. the great thing about all this is that it just works without messing about! i was especially happy that the sort method only acts on those "id's" that i am currently working within my "show" view and NOT all objects i.e. it updates the positions for those snippets in my current page, not all snippets. the acts_as_list gem is optional for me in that my position attribute is optional but i may also end up with several snippets with NO positions by default so i'd sooner have positions added by the acts_as_list gem on new snippets - even if the calculated 'next position' is not scoped to my current page model. it's no big deal because as soon as you reorder your snippets it all sorts itself out!
How would you go about doing something similar with jQuery?
I mean, pure jQuery, without the jRails plugin...
Andy,
Try this:
http://www.wil-linssen.com/extending-the-jquery-sortable-with-ajax-mysql/
What's the difference between content_tag and content_tag_for? I'm always using content_tag in my rails projects.
Don't forget to mention that the SQL indexes on the 'position' column MUST NOT be unique, because of the temporary duplicates created by the progressive updates in the sort action.
an idea for next weeks rails cast. expand upon this using categories. in an application i have now, i have my faqs linked to a specific category. my users can order the categories themselves in addition to the group of faqs under each category.
How hard would it be to extend this to nested lists, using acts_as_tree? In particular, dragging a sublist item to another sublist, or making it a parent (out-denting)?
Hi Ryan,
I am happy with your railscast video but i can't download source code.
When I tried to download source code of all episodes i got source code upto episode no.136 only.
Please check it out of there is any prob. in git.
Cheers,
:)
If any of you out there are trying to use Ryan's technique to sort <tr> elements inside a table, make sure you
(1) read the documentation for Sortable.create, especially the important information under "Notes" (see http://wiki.github.com/madrobby/scriptaculous/sortable-create), and
(2) pass :tag => "tr" to your call to the sortable_element helper method.
Ironically...the most valuable thing I got out of this was "each_by_index", haha! Found myself using a separate indexer "i" a number of times, had no idea this existed! Thanks Ryan.
This is what I do with jQuery: http://henrik.nyh.se/2008/11/rails-jquery-sortables
It also uses a single query to update the index, which could be used just as well with Prototype.
Thanks for the example! I needed to do something like this today, and while I could have put it together myself from the pieces, your example is a complete picture of how I wanted to implement it, even down to the collection RESTful action :) And to think I stumbled across it through pure luck from Google, even before iTunes had downloaded today's video from the podcast.
Awesome as usual... Just wondering is this the same for organizing a gallery of images? If they are not just a list but in rows and columns?
Thanks for the episode. I've learned a ton from you and am very thankful. If I can vote for a future episode topic, I'd like to see something about using an asset service like Amazon S3 with Rails. I have some upcoming projects that want to do heavy video streaming and have been thinking about using something like S3 for the application. Thanks!
I JUST finished figuring out this exact same thing, and then a railscasts comes along! Crazy
Thanks, that's what I needed!
But in my app, each user will have the power to sort the list in his own way.
I'm trying a "rich join table" with (user_id, item_id, position) to relate a item to a user and to know it's position in relation to this specific user.
But I keep getting errors. I know this insn't very clear... But if someone can help me how to do something like that, I would be thankful!
Continuing:
To make it easier, I am logging successfully the data that I want:
item_id: 18, position: 1 and user_id: 1
item_id: 38, position: 2 and user_id: 1
item_id: 29, position: 3 and user_id: 1
item_id: 25, position: 4 and user_id: 1
item_id: 33, position: 5 and user_id: 1
I just need to save/update this in my database.
Ryan, I apologize about the semi-offtopic, but I don't know, maybe someone wants to do a personalized sortable lists too =D
Yeah! I made it!
Maybe it's not the best way to do that, but it's working.
If someone wants to know how I did it just reply here. For now I'll say sorry about the "flood" and thanks!
PS: Ryan, feel free to delete my 3 comments =)
Tutorials like these, the ones that focus on the "basics" are crucial to making our community standout from other web frameworks.
All average rails devs should be able to whip off a sortable draggable list in minutes. This screencast makes a nice dent in the right direction. I know there is voting out on UserVoice, but I would strongly encourage you to consider extending a few additional ajax centric screencasts similar to this to move our cumulative ball further down the field.
Perhaps centering on a few of the other scriptaculous modules such as expandable-collapsible divs, inline editing, ajax tabs, sliders, etc.
Essentially a toolbox of the common UI patterns we are commonly asked to provide our clients but are not always entirely obvious to implement.
Kudos again,
-Rich
I am not sure how this will add position column to the faqs table.
script/generate migration add_position_to_faqs position:integer
Any idea on what's going on here?
@Mario, content_tag_for accepts a model as an argument, and it will give the tag attributes based on the model's name and id.
@pulkit, weird. Do you still have this problem? Perhaps GitHub was having difficulties.
@Jcooper, great question! If you just float the list elements to the left it should work. You'll also want to set the
":constraint => false" option on sortable_element so the item can be dragged horizontally as well.
@R Sturim, thanks, I'll definitely consider working on some more basic ajax screencasts in the near future.
@Shreyans, Rails is doing some magic here, it parses the name of the migration and knows we're trying to add the position column to the faqs table. This was added in Rails 2.0, see the episode on that for details.
http://railscasts.com/episodes/83-migrations-in-rails-2-0
I'm currently working through implementing this on a has_many through association. Are there any tricks involved in doing that?
Sorted it (no pun intended, really). I had to do the for each on the association model in the middle. It looks like there are a few more db accesses to get anything from the models I really want though as each call to the associated model on the other side must get loaded afterwards.
Do you know how to use this to sort by more than just position? I want to sort people with drag/drop, but maintain two columns, male and female. Can u sort by, say, position and sex?
Nice tutorial! :) I've been following these for a while.
However, is there any simple way to drag items between lists, or to drop an item into a dropbox?
Great tip !! Thanks.
However, I think that the sort action
could be made to be more efficient. If I understood right, it generates a separate update for each line, every time the user drags a faq. Better to generate a single update string and execute it after the loop (in the sort action).
Using this method to update the positions of records, how do you get a sweeper to fire? The only way I've been able to do it is with this method:
http://gist.github.com/94735
Unfortunately, it fires once for every record that is updated. Is there a better way to get it to fire only once?
Can this technique be combined with the dynamic list that you presented in #73? I would like to be able to add elements and sort them during creation and edit.
For a jQuery-based alternative that works on trees instead of flat lists, see http://blog.ronaldevers.nl/posts/6-rails-sortable-element-helper-with-jquery
Great stuff Ryan!
hmm ... tried doing this but for some reason my sort is not getting saved to the database in the position column ...
I have manually entered in page positions and they do sort properly but the position just doesnt get updated .... Any help would be fantastic.
I'm building a simple TODO list application and used this great tutorial to make my TODO list sortable. Thanks, Ryan! It worked! :)
Now, how do I make my TODO list also be nested? i.e. How do I use acts_as_list and acts_as_nested_set together (or is there a better way to do this)?
Thanks!
Here's something I found on making a sorted, nested list:
http://www.justinball.com/2009/01/18/heirarchies-trees-jquery-prototype-scriptaculous-and-acts_as_nested_set/
via
http://stackoverflow.com/questions/198047
It uses
http://github.com/collectiveidea/awesome_nested_set
but it seems sorta complicated. Got any simpler solutions?
Using Rails3 beta2, here's the routing code that works for me:
resources :faqs do
collection do
post :sort
end
end
Dear Ryan,
Thank you so much. One question I had about this screencast is, how on earth do you test something like this?
I use this functionality on many controllers, and extracted common controller actions as a module: https://gist.github.com/1030815
Wow, coming up to 3 years old and this is still a super easy way of doing sorting by dragging. I have just used this approach alongside your brilliant nested attributes tutorials (http://railscasts.com/episodes/196-nested-model-form-part-1) and it works just as well as the simple model example you use in this tutorial.
For me I have a Page model with nested attributes on a Snippet model (all very CMS based). If anyone was thinking of doing the same, go for it. I did this - it may help you:
1 - added a controller for the nested model - "Snippet" in my case (not needed otherwise) which just contains the "sort" method as you have it i.e.
2 - add the drag n drop code to my show view rather than my index view like this:
it helped me to keep the sorting feature out of the way of the nested attribute feature in the edit view for my parent model
3 - since i am Rails 3.0.x based i have added a default_order scope to my nested model to handle the sorting bit:
4 - for Rails 3 i have also used the routing approach added by Tyler Gannon in these comments i.e.
all works a treat. thank you for your excellent work as always Ryan!
glenn
p.s. the great thing about all this is that it just works without messing about! i was especially happy that the sort method only acts on those "id's" that i am currently working within my "show" view and NOT all objects i.e. it updates the positions for those snippets in my current page, not all snippets. the acts_as_list gem is optional for me in that my position attribute is optional but i may also end up with several snippets with NO positions by default so i'd sooner have positions added by the acts_as_list gem on new snippets - even if the calculated 'next position' is not scoped to my current page model. it's no big deal because as soon as you reorder your snippets it all sorts itself out!