Ajax Sortable Lists Rails 4

Ajax Sortable Lists Rails 4

___

Learn how to easily achieve a drag and drop sortable lists functionality in your rails app that updates via ajax

With me, is a simple to-do list application where users can create dummy to-do lists and displays them in card-like form just like in Trello. We want to enable users to sort the list by drag and drop so that they are displayed in the specific order the user sets them.

You can take a sneak peek at the final result

Getting Started

To achieve the drag and drop functionality, we will be using html5sortable jquery plugin. The reason I love this plugin as opposed to the widely used jQuery UI is its small size that means your page loads much faster while achieving the same functionality.

Grab the html5 sortable plugin form the Github page. You can find the js in the src directory. Add the html.sortable.js file in your vendor/javascripts folder.

Next, lets require it in our application.js manifest file

Loading Gist

Updating our Task Model

Our Task model has two fields, title and description. We need to store the position of each of our tasks and to do this we need to add a priority column which will store the position of our task inside the database. We will be able to sort our tasks by using this field.

rails g migration addPriorityToTasks priority:integer

Run rake db:migrate to update our database.

Integrating html5sortable

Let's take a look at our task's index view

index.html.erb

Loading Gist

As you can see, its pretty standard and all it does is render the _task.html.erb partial. I have added a .sortable class to the div that houses our partial, It is this class that we will call our sortable plugin on so that it sorts our tasks.

_task.html.erb

Loading Gist

Next up,all we have to do is make our task's partial sortable. In the tasks.js file, call sortable on our div with the sortable class

task.js

Loading Gist

The sortable plugin will look for a .sortable-placeholder class to use to show a placeholder while drag and droping our tasks. You can style it as you wish to suit your case

task.css.scss

Loading Gist

With this we should now have a drag and drop functionality

Our tasks in the list can now be dragged and dropped into any position, but the new order isn’t persisted back to the database. When we reload our page, the tasks are shown back in their default position.

Persisting Changes

We will add a data-id attribute that will hold the id of the task and another attribute data-pos that will hold the position of the task in the DOM. We will then send this attributes to our rails app each time the user has sorted the list and update the task's priority accordingly.

_task.html.erb

Loading Gist

We then use jquery to set the data-pos on each of our tasks

task.js

Loading Gist

When we inspect our DOM you can now see that jquery did set the data-pos for each of our tasks

Now that we have this in place, all we need is, after the user has finished sorting the tasks, we have to send the updated order back to rails. To do this, we will listen to the sortupdate callback function provided by the html5sortable plugin. This function is triggered every time the user has stopped sorting and the DOM position has changed. We will add logic to get the updated order inside this callback function.

tasks.js

Loading Gist

You will notice in the ajax call, we submit a PUT request to the sort_tasks_path (tasks/sort). We don't have this url set up yet. In our routes.rb

Loading Gist

Next up, we will have to write a method in our TasksController that will store the updated position orders. The controller currently has the standard RESTful actions for listing, showing and creating tasks. We will add a method sort to our tasks controller that will be responsible for storing the updated task order as specified by the user.

tasks_controller.rb

Loading Gist

The sort method will loop through the order parameter and update the priority for that Task. Each parameter contains the Task id and its new position. We find the Task by its id then update the priority attribute. Since we don’t need to send anything back from the AJAX call so the method finally returns nothing.

We will arrange our tasks based on the priority column. In the task model, lets add a default_scope that orders our tasks based on the priority column in an ascending fashion.

task.rb

Loading Gist

And that's it!! Now when we drag the tasks about and then reload the page the items new position is persisted to the database. Hope this was helpful, have any questions or suggestions? feel free to use the comments sections below. You can also clone this app on my Github Repo.

Happy hacking!


13 Comments

___

0d7f52961866e3dd30a1bc9eae7f3ef777cb7cd0

Stefflan00

26 Dec 14

Do we have the chance to put any task on top? I mean we can put the first(top) task to an other place but we don't be able to put for example the third task to the top.

0d7f52961866e3dd30a1bc9eae7f3ef777cb7cd0

Stefflan00

26 Dec 14

Ok just one more thing to add in .sortable => list-style-type: none; Otherwise we see a bullet before the first task.

Af93b0dc6784881c1608e7ee408020e9c3e70c31

Simon Mutie

15 Jan 15

Its great tutorial. Perfect skills.

7a1e82a9e222cbf877a14387534450b2908aa877

Bob Walsh

26 Feb 15

Great tutorial and excellent code. One issue though in the repo. If you create 3 tasks, you cannot drag task 3 "in front of" task 1. It defaults to position 2. Not a big deal since you can then drag task 1 below task 3 (in second place).

58868bf26f19c2b3b588d62cbb5b206e8c84e38f

benjamin mwendwa

23 Mar 15

Great tutorial Joseph.

Af73b63e2614c703c146e827357226d99a309d1c

scramlo

10 Apr 15

Just FYI for anyone who had an ExecJS error: I needed to convert the JS to CoffeeScript.

Af73b63e2614c703c146e827357226d99a309d1c

scramlo

10 Apr 15

My data-pos doesn't seem to be iterating through each li... do you know why this may be? JS: var ready, set_positions; set_positions = function(){ $('#move-me').each(function(i){ $(this).attr("data-pos",i+1); }); } HTML:

D89dbcbb9cd13f7b3d5efeb135c793619c4b1b33

Christopher V Castillo

17 Aug 15

Thank you for such a good tutorial I want to create two columns and store the position of item dragged to column 2 or back to column one I was able to do it with this connectWith: '.connected' but i can't save it into my database! Do you have any ideas?

511f717a3d3fe82dfe2524054c3d8b2a08fad926

Sean Kelley

04 Oct 15

This works on development but does generate js error in console: Uncaught ReferenceError: module is not defined(anonymous function) @ html.sortable.self.js?body=1:433. When I push to heroku it stops working completely. Any ideas? I am using rails 4.2

A522d7c817d214ce40372df5d823acf92ede1041

sri26

30 Oct 15

i was getting conflicts when apply the sortable to child level... i have applied sortable to parent level i.e to a div panel, and also i have applied to list item in the div while i was trying to sort the list items parent(div) and it is not applying to child level

A522d7c817d214ce40372df5d823acf92ede1041

sri26

30 Oct 15

i was nested sortable with this ajaxs sortable in rails 4

18d6db2d7cae02af26cd0f0df97eb18f943810b2

aakanksha0402

01 Aug 16

Loved the article. Its simple and straight forward even for a newbie like me. I faced a CSRF-Authentication error, however, once solved. I got exactly what i wanted. Thanx a ton

943379c1a3a8ba0197c3fcd42ce3e4f871eb54a3

Camilo Sad

05 Dec 16

Great article. Really helpful. Just one little thing that I had to change, using Rails 5 and turbolinks: Instead of - $(document).on('page:load', ready); I used - $(document).on('turbolinks:load', ready);

Latest Tutorials

___

Private Inbox System in Rails with Mailboxer New

Introduction It's been quite a while since my last tutorial and since then I've recieved alot of requests by email to implement a private messaging system ...

Ajax Sortable Lists Rails 4

With me, is a simple to-do list application where users can create dummy to-do lists and displays them in card-like form just like in Trello. We want to e...

Managing ENV variables in Rails

Often when developing Rails applications, you will find a need to setup a couple of environment variables to store secure information such as passwords, a...

Gmail Like Chat Application in Ruby on Rails

Introduction We are all fond of the Gmail and Facebook inline chat modules. About a week ago, I came across a tutorial on how to replicate hangouts chat...

Fast Autocomplete Search Terms - Rails

Introduction In many cases you find that you need to introduce a global search in your rails application i.e. search multiple models at a go using one form...

Load more scroll top