Skip to main content

Sortable Drag and Drop Discussion

General • Asked by Chris Oliver

Just a heads up, in your Gemfile, bootstrap 4 beta no longer uses tether for tooltips, now uses popper.js which is now a dependency of the bootstrap 4 gem

Yeah! Popper is nice to have instead. Screencast was using an old version of my Rails template which has been updated already, just hadn't done a git pull recently on that machine. Should update that in the repo.


I'd love to see you go further into this topic with Vuejs!


I'd DEFINITELY be interested in the Vuejs version - I've got an app in mind that it would be very helpful for...


This approach for updating reordered records will produce O(n) queries. If you use Postgres, it is possible to do the same operation with a single update: https://stackoverflow.com/a... The only disadvantage here is that ActiveRecord can't do queries like this (correct me if I'm wrong), so it will take direct SQL execution.


+1 for VueJS as well


Here's another implementation that avoids excess queries and lets you use the standard update controller action. It uses the insert_at method that acts_as_list provides to move the item within the list:

https://gist.github.com/dva...

# app/models/question.rb
def new_position=(position)
insert_at(position.to_i)
end

Make sure to add :new_position to permitted params in questions controller

# coffeescript
$(document).on 'turbolinks:load', ->
$('.sortable').sortable
axis: 'y'
handle: '.handle'
update: (e, ui) ->
data = new FormData
data.append "question[new_position]", ui.item.index() + 1
Rails.ajax
url: "/questions/#{ui.item.data('question-id')}"
type: "PATCH"
data: data


Thank you this was an awesome tutorial, will definitely be watching more from you!! 

A few pretty basic observations/questions:

(1) When I use: 
Rails.ajax
nothing hits the server after the drag/drop is complete. 

I changed to:
$.ajax 
and that fixed the problem. Any ideas why the former did not work and the latter did?

(2) Instead of 
//= require jquery-ui/widget
//= require jquery-ui/sortable

I needed to use
//= require jquery-ui/widgets/sortable
to avoid an error message. I suspect this has something to do with either (a) a new version of jquery-ui or (b) my lack of understanding of the asset pipeline.

(3) My implementation required me to the skip authenticity token on the sort method with:
skip_before_action :verify_authenticity_token, only: [:sort]

How does the code in this tutorial work without skipping the authenticity token verification?

Thanks, as always, for such wonderful tutorials!

Thanks Joel!

Some answers to your questions (not exactly in order):

1. Rails.ajax is the new replacement for jquery's ajax ($.ajax) now that Rails no longer comes with jQuery. Rails.ajax is also smart enough to include the authenticity token in every request which is why you don't have to do #3. 

3. For your code, you should include the authenticity token in the request instead of disabling the check as you'll open yourself up to security vulnerabilities by turning it off.

2. jQuery-ui may have moved sortable to the widgets folder since I recorded the episode. Things are always changing so you'll often run into little changes like that.
Thanks, Chris. Strangely, Rails.ajax doesn't fire an ajax request for me even though $.ajax works fine. I'm using Rails 5.1.5 and I've confirmed the rails-ujs file is included. Good to know about the authenticity token being included in every request with Rails.ajax.
hey guys thank you both, Joel your comment helped me to solve my problem. And Chris, man I love what you're doing, I started to learn Ruby and Rails some months ago and you already helped me a lot with your tutorials. What you're doing is something that money cant pay honestly. Keep going 

The same was happening to me when using Rails.ajax(), I found this online and now it works:
$("#sections").sortable({
update: function(e, ui) {
Rails.ajax({
dataType: 'script',
url: $(this).data("url"),
type: "PATCH",
beforeSend: function() {
return true
},
data: $(this).sortable('serialize'),
});
}
});


Would love to see a Trello clone!

Hey Seph! I did a whole series on it here: https://gorails.com/series/vuejs-trello-clone-in-rails

Hope you enjoy it!

Hi Chris, I would need to be able to sort items in a list as you've shown in this episode, but also move items between linked lists. How would you implement this? Problem is that in this case I need to remove the item from the old list and add it to the new list, besides updating the positions, and the new positions should be correct in both lists without leaving gaps in any of them. So I guess the serialize trick and just updating positions in batch in the controller would not be enough? I also noticed that when you move an item from a list to another, jQuery UI Sortable triggers two update events, one for the source list and the other for the destination list. Thanks a lot in advance for your help!
Update: actually... it seems to work just fine. The two requests update the two lists correctly with no other changes. Thanks! :)

Another question.... how would you go about testing sorting with Capybara/system tests? Thanks

If you know you are not going to respond to our questions, why do you keep the comment session on the blog?


Hi Chris,

This is such a useful video! With a little help from your friendly neighborhood GoRails Slack channel I got it (mostly) working, but for some reason it's not serializing correctly. According to my server log, it is sending PATCH data to the database:

Started PATCH "/tasks/sort" for 127.0.0.1 at 2018-10-20 11:16:06 -0700
Processing by TasksController#sort as */*
  Parameters: {"task"=>["2", "8"]}
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ?  [["id", 1], ["LIMIT", 1]]
  ↳ /Users/lizbayardelle/.rvm/gems/ruby-2.5.0/gems/activerecord-5.2.1/lib/active_record/log_subscriber.rb:98
  Task Update All (0.2ms)  UPDATE "tasks" SET "position" = 1 WHERE "tasks"."id" = ?  [["id", 2]]
  ↳ app/controllers/tasks_controller.rb:27
  Task Update All (0.1ms)  UPDATE "tasks" SET "position" = 2 WHERE "tasks"."id" = ?  [["id", 8]]
  ↳ app/controllers/tasks_controller.rb:27
Completed 200 OK in 3ms (ActiveRecord: 0.5ms)

But for some reason it always stays the original order on refresh. Any hints as to what could be going wrong?

The only difference between my app and the example app is that I had to have the .sortable act on a class (.taskWrapper not #taskWrapper) because I have the tasks in a partial that's being rendered more than one place on the page. Could that be affecting it?


How to make it work with Mango?


I can't make it work with serialize: I see the only params sent to my controller are {"controller"=>"tasks", "action"=>"sort"}


After following along to the end of the video, I stil couldn't get my records(feature_package to update, the params getting passed were Parameters: {"packaged_feature"=>["321", "1"], "id"=>"sort"}, apparently because of the PATCH request it was looking for a specific record id automatically and changing this to a POST in my ajax request and my routes file worked for me.


Login or Create An Account to join the conversation.

Subscribe to the newsletter

Join 22,346+ developers who get early access to new screencasts, articles, guides, updates, and more.

    By clicking this button, you agree to the GoRails Terms of Service and Privacy Policy.

    More of a social being? We're also on Twitter and YouTube.