Implementing Drag and Drop Functionality into a Ruby on Rails 5 App
Building in the ability for users to drag and drop elements is a popular feature for web applications. In this guide we're going to take a step by step approach for building out a completely drag and drop feature for a Rails 5 application, including how to connect the jQuery code to the Rails app so the drag and drop items permanently change values in the database.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

This is going to be a very exciting guide in this lesson we are going to walk through how to take our drag and drop interface which right now is simply in the front end and integrate that into Rails app so that we can have what happens here in the browser and actually go and update what's going on inside of the database. I think that's very exciting and it's a feature I get asked to build quite a bit and I'm sure that you will as well. Now this is going to be a decent sized lecture in terms of how long it goes and it's going to take a while to build this out. One question sometimes I'll get or suggestion I'll get from other instructors is you know trying to break these down into smaller chunks. You know a lot of instructors like to do cute little 5 - 10 minute videos. I'm not a fan of that whatsoever. In a perfect world, each one of these videos would be about 20 to 25 minutes long because my goal isn't to give you cute little Rail's videos there to help you become a professional developer and you cannot become a professional developer in little 5 - 10 minute chunks. It takes serious time to produce serious results. So just so you have kind of a little bit of idea of the way that I personally like to work and also how I like to teach so that if you're wondering why some of these do go longer it's for that reason I follow what's called the Pomodoro Technique which means that I break my day into a series of twenty-five minute chunks and after that 25 minutes is up I go take a five minute break come back knock out another 25 minutes and go on and on like that. I found it's a very helpful tool in order to be productive and to get quite a bit done in a short period of time. I know I just lengthen the length this video just by giving that explanation but I think it is something that is important to have in your mind.

So what we have to do first? Let's talk about that. Let's open up the portfolio item partial. So this is going to be the partial that's called just a review. Each one of these represents a single partial call. So when we call the partial for our portfolios collection it's going to render one to three all the way down until the very end. So this is our partial call.

medium

So what we need is a way for our Javascript code to know the data to know the value and to know the id of what each one of these portfolio items are right now all it knows is it's grabbing elements on the page. It's moving them around but it actually needs to know what element it's grabbing because it's going to have to pass that data to the Rails app. So the first thing that we can do is we're going to use a attribute here called data dash id and we're going to use erb inside of it and pass in portfolio item dot id. So all this is is it is grabbing the value of the id for each portfolio item. So each one of these cards now will have something that distinguishes it that we can go in grab in our Coffee script code and that's the only change we need to make in that partial.

"<%= portfolio_item.id %>"

So if I hit refresh now and if I go and click inspect we should be able to see this Id populating here. So I go and select the entire card. You can see right there we have a data id of 21 so that's what the idea is there. Here the next one over the data id is 1 next one over 4, 5. So on and so forth. So that's good. That's the first step is we need the ability to grab that portfolio item so that our Coffee script file is going to know what to do with it. And speaking of that let's come and let's open it up. So right now I hate to tell you this we're going to have to write a lot more Coffee script code in order to get this working. The only reason I say that is because if you're going through the scores and you have not spent a ton of time with Javascript some of this is going to look a little unfamiliar but I don't want that to scare you away. Simply focus on the type of behavior we're building in and less on the syntax. One thing I can promise you if I was writing this in pure Javascript you really wouldn't like it because it's much less intuitive and the original guide that I showed you in the very beginning of the section was in pure javascript and so I translated that old Coffee script in order to make this work along with changing the things that are needed for more modern versions of Rails. So we have our ready method or a ready function here. The next thing that we need to do is we need a way of setting what are called data positions.
So we have data ID that's that special little attribute here. But we need the ability to set data positions so we're going to create a function called set positions set this equal to undefined right here and now we can define the method. So I'm going to say set positions and we're going to set this equal to the value of this function. Those functions are going to be stored inside a set positions and we're going to simply first grab our card element. So I'm going to say. Card except we have to do a dot. So all we're doing here just like CSSA were grabbing any card class. But this is only going to be called inside of here. So we don't have to worry about your card class in other parts of the application because it's only going to work when it's being called on something that has the sortable class added like what we have here. So here we say dot card and that's the first thing, now what we need to do is we need to iterate through each one of these. Thankfully Coffee script has a method that looks a lot like Ruby and this is part of the reason why you will find many Rails and many Ruby developers like to use Coffee script instead of pure Javascript because there are more similarities between it and you compared to regular pure type of Javascript. So you see each and then we're going to pass in what you would know on the Rails side as a block variable. This is essentially just going to give us the element that we need. Now we're going to pass in what happens inside of that. So give a couple more spaces here and we're going to grab the specific instance. So just like we would usually call self Javascript has the concept of this so it's meaning this specific card in this instance and so i am gonna say this attr which is short for attribute. Now we're going to create something called data dash pos for position and we're going to sign this to i which is the value of the card there plus 1 and that is simply going to incremented up. We're going to return and return that value and that is all set positions is doing.

So it's essentially grabbing the values and then it's going to set this new attribute of data position. Kind of similar to what we had with the data id. But the difference is data id is the value that is set via Rails its whats set from the database and data position is what we're going to use in order to keep track of that. So that is the first thing that we're going to do. So now with this in place the next thing we're going to do is come down into our ready function and this is where we're going to start adding a little bit more to it. So the first thing we're going to do is we need to call the function that we already created. So we're going to call set positions. This is going to give us access to each one of those positions. So now that we have that we are going to go down and we're going to implement exactly what we had before. So we're going to implement the sortable library and that's all we need at that point. But now we need to go and we need to perform some updates. So we're going to copy this not the full sortable but just our selector. So I'm going to say on sortable I want you to sortable and then inside of this we're simply calling the method but we're going to change another method on it called bind and then sort update. Even though that was only a few words that still is kind of a lot of code especially if you've never seen it before. What in the world is sortupdate. Well, let's copy this and let's go ask that question to our library.

If I hit F and sortupdate this brings us to one spot in the file that is called sortupdate and it's surrounded by a lot of very confusing Javascript code centrally what this is going to do is this is going to give us the ability to update the sorting. So it's going to grab the item based off of the drag value. And this is going to help perform that change. So that is just so you know that I'm not just making the word sortupdate up. It's coming from here. Now a natural question to ask when ever you would see someone in a screencast do something like that is how in the world would you know how to do that. Well, that's where the documentation comes in. You're usually any good library is going to come with a set of instructions the same thing is if you were to buy a piece of furniture you typically are going to be given a set of instructions and if you want to build that in that furniture properly you'd read the instructions. Well, same thing here pretty much every library every gem everything like that is going to come with a set of documentation instructions on how to implement it and they'll say things like pass in the sortupdate message to bind in order to get this working. So just so you can have an idea because that's a very common question I'll get when ever I am implementing additional libraries. How do you know where to find those things. Usually, the answer is the documentation. Now inside of this, we're going to pass in a few items we're going to pass E as a variable is just an argument and then inside of this we're going to go perform some more processes.

So this is going to be indented. A good rule of thumb with Coffee script whenever you see the little arrow the next few lines are at least the next line is going to be indented because what you're saying is I want you to go and perform these processes that are nested underneath here and indentation in Coffee script is very important so make sure you're matching that. If you have all of them lined up then you're going to end up with some very very challenging code one to read. But then also for the parser to process. Ok so now that we have that we have our arrow. The first thing we need to do is we're going to create an array and the cool thing is with Coffee script you can call array the same way that you had in Ruby. So I updated underscore order equals an empty array. Now from here what we're going to do is we're going to call set positions again. Now you may kind of wonder what that's going to do and what it's doing is it's going to allow us to actually adjust that. So we're going to be able to take the items that have been sorted and then set positions because remember set positions goes through this full collection and sets the data positions so we can call this when ever we need to kind of get a refresh on what the positions are. So that's the next thing is we click on. Or we call set positions and now we're going to call our data again. So in order to do that to give dollar and in a string dot card and let's iterate over these items some say each i which is similar to how we do it in Rails with each do and then you're passing in a block variable to pass another processes as if you count these arrows. This is a nested set of processes one ready happens whenever the page loads. Then this happens any time someone clicks and drags items on the portfolio. Now this happens whenever this sort update occurs and now we're going to iterate over and everything inside of this is what is going to be changed. So inside of each what we're going to do is we're going to call our updated order array and we're going to call a method called push which is going to take a few arguments. So give a another carriage return. It's going to take an id and that Id is going to be the value of this followed by data followed by the argument of id. All that essentially is doing is we're saying that take the id that you grab from the card and then go and add it into the updated order array. That's all that that's doing. And then you need to say position and i plus 1 which is going to increment the position. Now come back go backspace type return and then the last thing that we're going to do is pretty cool we're going to now actually communicate with Rails and the way that you can do this in Coffee script and jQuery and this is one I definitely want you to pay attention to. Obviously, if you're following along you don't need to pay attention to all of it if you're wanting to build it. But this specifically is something that you're going to be doing a lot in the deep dive. I'm going to give even more of a base case you can understand how it works. But if you are ever building functionality in Javascript that you need to go and communicate either with an outside API or with Rails itself this dollar dot Ajax is most likely going to be the way you're going to do it. This gives us a direct line of communication with whatever we want to talk to. So here this takes a few arguments. The first is the type of communication. So we're going to call put. Now let's talk about the type really quick. And in fact I'm going to switch to the terminal type

rake routes | grep portfolio

This is going to give us our full list of portfolio items and put is a very important word. It is considered a verb. If you don't remember it and you can see it's right here. So what put does is it's what you call when you want to update a value. So right here what we're saying with Ajax is I want you to make a put request to the path we're going to pass in and I want you then to update the value in the database. That is a very important thing to keep in mind because that is going to be how we're communicating and that's what that swept everything we're trying to do right now is based around. So now that we have that now we need to let the application know what we are communicating. And the way we're going to do that is we're going to call the path that we want which is portfolios. Slash sort. Now you may wonder where is that sort method coming from. Well we are going to create it. We're going to have to go and create a controller action called sort that's going to manage this process. And then the last thing that we need to do is pass in what data is being sent to sort. So we're going to send in a params hash. So it's going to be a param and it's going to be in our params hash that we can access from the controller in order to save order and then updated order. So all essentially all that's going to do is it's going to take our updated order array. It's going to pass that into the orders hash there and then we can use it to update all of the parameters inside of our portfolio. So that is actually it. On that side. So you hit return because that is one of the differences between our set up with what we have when I actually had this return with how Coffee script and Javascript works compared with how Ruby works. Ruby is a little bit more intuitive and you don't have to manually type in these return statements. Ok, so that is all there. Now we can actually test this if I open up the real server. It's not going to work yet but if our code is all right we should be getting a very specific error. We should be getting an error that says that this route does not exist. So let's go and test this out and close this out and hit refresh.

The first thing is good. That means that we didn't have any errors on in regards to syntax for the page. Now if I click and drag everything there is still working. So that's all good. Now let's go and look at the terminal because if we are having the right kind of communication with the app that our Ajax connection built in we should be seeing a routing error and there we go. Look at this active record, record not found couldn't find portfolio with id sort. So essentially what is happening here is look it's passing in this parameters and it's passing these in with an id it thinks the id sort. Because if you take a look at our portfolios if you remember portfolios slash anything it's going to try to think that there is some type of portfolio that we're trying to update. So what Rail's is doing is saying ok I can not find any portfolios that have an id of sort. So I don't know what to do and that's why it's throwing that error. But that's good because that's the next thing we need to do is update our route. So we're going to come here and there's a pretty easy way we can add this and resources is a method that can actually take a block and inside of the block we can create our put statements, so I'm gonna say put and then pass in the method or pass in the path of sort and say on collection. So that is going to do is it's going to say when ever you see portfolios slash sort then I want you to go do something else.

large

So if I come here and open up the portfolio controller and come right below our index I'll create a no other method here called sort.

medium

Let's come here and end our server session and type

rake routes | grep portfolios

We should be able to see our new portfolio sort and there you go. We now have a new method here that we can use with put. That is called sort portfolios. So all of that is working. Now the next thing that I want to do is I want to see what our error has been changed to. So now we are going to have something else because we have a controller action and we have a defined route that we now should have some other type of error that's popping up or some kind of attempt to insert the parameters into an empty method. So you click and drag it out and now if I come to the terminal Let's see what we have. So right here it's says started and then it says processing it's passing in all the parameters. Notice how it's passing in a parameters with the order hash which is exactly what we want. And then it's passing in the id map to the position. This is perfect. So now this is going to be how we can update the position because we're saying hey if it has this id and this position I want you to change the value. I definitely recommend for you spend a little bit of time going through this data. Make some changes and see that changes in parameters to see exactly what's happening in the back end because this is definitely something that is important to understand if you're having a hard time. Kind of understanding the whole process so take it one step at a time.

Look at this value, these set of values here and that should hopefully give a little bit clarity as well. OK, so we have this it's working. But what was the error? The error said no template found for portfolios controller sort. So that's perfect. That's exactly the error that we want. Because remember a controller action by default is going to go look for a view. So what Rails did is it went to sort and it said wait a second I I was routed to the right place. I see this action right here. But then I went to views portfolios and I don't see any sort of view and that's because we don't want to render a view. We simply want to perform some actions. So let's give Rail's what it is asking for. So first thing is we want to grab the params. Now, what are the parameters again? They are order and we can test that out by coming in the terminal and we can see that we have the access to parameters order. Now that we have that we can see it's a collection so we can just iterate over it. So I am gonna say each do and this is a set of keys and values. So I'm going to pass in key and value as the block variables and inside of this we simply have to call portfolio dot find it's going to look for the id so we need to find the value and that's a hash of id. Now, this is getting into how you can parse hashes. So right here we grabbed order and so each one of the orders were iterating. So the first one is going to be zero. It's a key of zero and then it's value is this hash. So we're grabbing this one first because remember grabbing the id and we're saying I want you to bring me back the portfolio with an id of one so it's taking that. Then from there what it's what we need to do is we need to call the update method and update the position. Now if you remember all the way back just a few episodes ago where we updated the positions in the terminal. You may notice something similar. This is exactly what we're doing we found a portfolio item we click we typed update and then we passed in a position. So what position are we passing in?We are going to pass in the value but instead of passing in the id this time we're passing in the position and that is all we need to do. The last thing we can do here is we can just say render and then nothing mean true. So what this is going to do is it's going to bypass the traditional Rails type of process where it goes and looks for a view and it's going to say ok we're done. We are simply communicating with the database. We do not need to go and try to render a new view so that I believe might actually be everything.

medium

Let's come back to crome hit refresh. Now, this is going to be the test. If I click on updated portfolio. This worked before this worked before we did all of our implementation. But now let's hit refresh again and see if it works and look at that we now have persistence and I'm going to pull this back so we can see it along with the terminal because I think it's really important to see exactly what's going on here. At the same time remember before when we made any changes here nothing happened in the terminal. Well now let's see what happens if I click on portfolio 3 and make this the first item. Look at that it is going in it communicates with the database and it renders. Let's do it again this time portfolio 6 in the number two position it went and it rendered it and now portfolio number six has been updated and now has a position of 2. So that is working beautifully. Very nice job on that. If you went through that I can tell you this. This is not a trivial feature. There are plenty of Rails developers even experienced Rails developers who if you gave them this task would have a very difficult time going and implementing it. This is not an easy thing to do. So if you followed along and you got it then fantastic. If you follow along and you are just completely confused then go through it again and go through the code and simply keep on repeating it until it makes sense. Nothing that we did was magic. There is nothing in there that you won't be able to learn. You're going to be able to do this and then you're gonna be able to use it for your own applications in the future. So anytime someone asks you to build a drag and drop interface you're going to know exactly what to do and you're going to be able to have the code already because this is going to be in your git hub. You can go in reference. So that is pretty cool. Now let's hit clear and type

git status

See everything we did get and

git add .
git commit "Implemented live persistent position updates for drag and drop interfaces"
git push origin javascript

Now that is done let's go and let's close this off and pivotal tracker. There is one more thing that we have to do before we get in the coffee script deep dive. That is to implement our security measures so it's just a implement security because one thing that is a little bit of a problem is yes you can use our dragging your drag and drop interface. The problem is so can everyone else who accesses your application. That's probably not what you want to happen. I don't think you want anyone coming to your app to be able to click and drag items and change the positions however they want. Maybe you do maybe you're building an app where you want that but not for your portfolio. So in the next guide we're going to go through and see how we can implement our security measures the same way that we did for our forms and for any of the other items that we needed authorization for. So we're going to take our Peter gate methods implement them in our drag and drop interface so that we can have that security.

Resources