Building the jQuery Functions for Processing Comments and Connecting to ActionCable
This is going to be an extensive guide on how to build a set of jQuery functions that manage the data flow for our comment feature. Additionally, these functions will manage the connection between the user's input and ActionCable.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

So far in this section, we have essentially built out a skeleton for how our comments are going to be displayed and how users are going to be able to type comments in. But none of it's functional, right now it's kind of all for show. We do have the back end so we have everything prepared for how it's going to store the data. And we have the ability to create comments and perform all of that kind of logic. But now we need to bridge the gap. We need to build a connection between our form and everything that's going to happen in the back end. And this is where ActionCable is going to come in. Now before I get started I want to make one observation and that is pretty much everything we're going to be doing from here on out is going to have a very strong Javascript focus and if you are not that familiar with Javascript, Coffeescript and different things like that then some of it may kind of seem like it's just out there and doesn't make any sense. If that's the case I don't want you to feel intimidated or just frustrated that you aren't understanding every single thing that's happening. Instead, I think the best approach is to first simply go through and see exactly what's possible. That's the very first thing I like to do whenever I'm learning something new is I don't try to understand every part of it or else and I'm going to get stuck on one little thing, get frustrated and then my first reaction is going to be that I want to just quit. Instead, I kind of look at it from a very high level just to see everything that is being built and see what's capable. And then I let that kind of excitement on seeing all of the cool things that can be done help drive me to understand it on more of a line by line basis so that's kind of my two cents on it. Because we are going to be going through some things that definitely are categorized more in the challenging realm and I don't want that to scare you away from it because there are some incredible things you'll be able to learn but it will take some practice because some of these things are definitely a little bit more advanced. With all of that being said let's start.

I'm going to go to app/assets then I'm going to go to javascripts and you can see that we have a directory here called channels. This gives us the ability to have any specific javascript files that are related only to channels and to store them there. So I'm going to right-click hit new file and here I'm just going to call this...

blogs.coffee 

and that's because we are going to be using Jquery, but we're going to be using the coffeescript syntax in order to build it out. So I'm going to say...

jQuery(document).on 'turbolinks:load', ->
  comments = $('#comments')

jQuery and document and remember what that means is that we want everything that's going to be nested inside of this to occur whenever this file is called. So say on and then turbolinks:load. So what that is essentially going to do is it's going to connect us right to turbolinks and just to give you an idea what turbolinks is. Turbolinks is Rail's way of trying to load all of your files in a very performance oriented kind of mindset so that pages can load very fast and it's a great tool but it does have a lot of Javascript happening in the back-end and something that used to happen a lot was that you would build a crazy Jquery kind of function and then nothing would happen on the page. And it turns out that it wasn't even your jquery code that you wrote that was the issue it was actually that there were some things happening where turbolinks was overriding it or your jquery method, even if you were calling it the app itself was not calling it. And so in Rails 5 this has improved quite a bit. And now what we have is turbolinks and I'm a little misspelling there should be turbolinks:load and this should make it so everything we put inside of here is not going to have any turbolinks conflicts. I'm going to save this file. And coming down I'm going to create a variable which is going to be a variable called comments that we're going to use throughout the rest of this function and I'm going to select something on the page. Now, this is jquery. So the way that this works is it's very similar to CSS So when I do something like this... $('#comments') it's going to look for something called comments and specifically because I passed a hash. It's going to look for an id that says comments so I'm going to save here. And one thing that we have not done yet is we have not added this to our partial. So let's come down and not to our partial I should say, to what wraps are partial. So if I come down into our views and I have blogs. I want to go to the blogs/show.html.erb and I'm going to wrap this code up and wrap it up in a div and give this div an id of comments. So that is going to be there.

large

And now let's actually test this out. I'm going to start up the rails server and once this goes I'm going to show you how you can test to see if your jquery is going to be able to find something on the page. As soon as this gets rolling. There we go. Let's come back to our jquery selector(blogs.coffee) here and see if this will work. So I have this $('#comments') with the hash so it's looking for an id called comments. And now if I refresh first we'll make sure that we didn't break anything and we didn't. Now if you open up the inspect panel and go to console and paste in all of that code where it's $('#comments') and hit return. You can see that worked and it returned a div. So what this tells us and it even shows this is a jquery selector. What this tells us is that our selector is working so what jquery is going to be able to do is it's going to be able to come to the page look for an id called comments and then it is going to store it in this variable right here...comments = $('#comments')

OK. Now with that done let's say...

if comments.length > 0

if this is > zero which means if there are comments available then we're going to perform some actions. So what actions exactly are we going to perform? Well, the first one is going to be related specifically to ActionCable So we are going to say...

  App.global_chat = App.cable.subscriptions.create {
    channel: "BlogsChannel"
    blog_id: comments.data('blog-id')
  },

So say channel. And we're going to create a channel here so we're not making things up out of thin air. This is going to be something that we can map to, called the BlogsChannel and we're going to grab a blog-id and we're going to set this equal to comments.data, blog-id. Now your very first question right here should be where is this blog-id going to come from? And that is a great question. What we're going to do is actually add this in. So let's grab this...(blog-id) Coming back to this same div right here(show.html.erb) we're going to create something called...

<div id="comments" data-blog-id="<%= @blog.id %>" >

And then inside of this grab the actual ID for the blog using embedded Ruby. So you know we have access to the blog instance variable. So I can just call it just like this...(<%= @blog.id %>) And this is going to give us access to the blog ID. And so this is how our comments are going to know what blog it's associated with because you may have remembered if you open up the comments_controller.rb you remember how we have a current_user.comments.build? This is going to pass in the current user's id so that the comment knows what user it's associated with. But that's not enough because we also need to know what blog the comment is associated with and this is the start of that. Where we can set the blog_id for the comments and be able to work with them that way. So that's going to be the first one.

Now that is just what we're creating. This is a very common pattern. When you're working with ActionCable and really any kind of node based type of processes is creating subscriptions, and subscriptions are ways of creating a data connection to some other APIor a module or something like that. So now that we have that let's come back(blogs.coffee) and we'll say...

connected: ->
disconnected: ->
recieved: (data) ->

connected and pass in a function call. Now we're not going to do anything with this. It's simply something that it's going to look for. If we wanted to add more advanced features then every time it's connected we could put in some function here...(connected: ->) that would be called. But for ours, we're just going to leave it empty. Disconnected we're going to do the same thing and then received. This is where things start to get a little bit more interesting. So received is going to be a function and it is going to take an argument of data now inside of this what we're going to do is say...

comments.append data['comment']

comments.append and then we're going to take the data that we got, and grab the comment from it. Essentially what that's going to do, it is going to take the content and it's going to append it to the end of our comments which is what we're looking to do. Essentially if you want a visual what this is going to do is we're going to type something in here hit post comment and then what got typed in as a comment is going to be added to the comments div because you have to think about exactly what's going on here in order to understand it. The way that Rails usually would work in order to load more information onto the page we would have to load the page again. So what jquery does is jquery bypasses that whole server-side connection requirement where you need to load the page to do something. And essentially what it's doing is it's almost like it's tricking the browser. So it takes the content and we are going to obviously communicate with the server to add it to the database. But what we're actually going to do is we're going to take a two-pronged approach. We're going to take the data we're going to pipe that into the database but simultaneously we're going to let the browser know and say hey we created a new comment. Can you just slide it in here and display it to users. So it almost kind of is tricking the browser to think that those items exist. So that's something that if you've never worked with jquery before and done things like you know created new items then that may seem a little bit weird but it is the way that it functions. A great example of this is something that we've already done with our portfolio form. Remember with our portfolio form when you add new skills. So when go in and you add new technologies to a portfolio item. Remember how we looked at the terminal and nothing happened? The only thing that happened in the terminal(which means on the server), happened when we hit submit everything else was only happening in the browser. And that's a very important thing to keep in mind. So that is what we want to do with the data is we want to append it when it's been received. Now the next thing we want to do is create a method called 'send_comment'

send_comment: (comment, blog_id) ->
     @perform 'send_comment', comment: comment, blog_id: blog_id

and this is going to take two arguments. One is going to be the comment itself and the next is going to be the blog_id because this is kind of just to remind you that's exactly what we need in order to know what blog the comment is going to be associated with. Now there is a special method here we're going to invoke called @perform and this is going to send the comment. It is going to wrap the comment up as a variable that our perform method is going to have access to. And then it's also going to do the same thing with the blog_id. Now that seems like it's kind of a pain because it's a duplicate. What that's doing is it's something that's necessary from perform in order to have access to that data. Think of it kind of like passing a local variable that the send_comment process is going to have access to. So that is that process. Now we can get to some more fun stuff. Now notice my indentation that was all the if block. Now I have moved back. So this is going to be lined up with the if. And now what we're going to do is we're going to look for a new comment. So we're going to use some jquery and let's find, using the hash a new_comment...

$('#new_comment').submit ()

Let's go, just because it's fun to let's come back to Chrome inspect and if we come to the console let's see if we can find a new comment. And we can! Another thing, let's see if we can do $('#new_comment').val() and see if we have access to anything. And right now it looks like we don't. So let's actually inspect this and you can see that we have access to new_comment. And let's take a look at everything inside of it you can see that there is a ton of things that we have access to all of this is related to jquery. And so there's a lot of cool things we have. Now let's take a look at the code itself. So here we have a form and we have the ID of new_comment. So this is what we're selecting right here

large

So let me come back now that we know that that is being invoked and or that we can call it. What we're going to do is look for a specific event we're going to say when 'submit' is pressed, so in other words when someone presses the form button then we want to do all kinds of good stuff. So we want to first, create a scope of 'this' which if you've never used this before this is going to look really weird but it's going to scope this to this...

$this = $(this)

Don't let that kind of weird you out. All this is essentially doing is saying that we want an instance of this event we want something we can work with so that we can work with the data. So if I come down here. We're going to create a variable called textarea and say...

textarea = $this.find('#comment_content')

And now we're going to find the comment content. So let's come back. So I'm just going to copy this. (#new_comment) And this is going to be #comment_content and let's take a look at this now. So if I come back into the browser and let's inspect this. If I come to the console and I do need to use jquery syntax(we need to use it here)

large

we don't have to right here...

medium

because we're grabbing $this = $(this) So we have access to find comment content. That's why we didn't have to put the $ in front of it. But here we have to.

So if I look for comment content you can see OK. Oh I need to wrap it up in a string. $('#comment_content') And now you can see that we have that. And now if I look for the value, look at that. This is how jquery can get values from text inputs. So the reason why I'm taking some time here to go through this is because a lot of this javascript code is going to look really weird and I highly doubt I'll be able to explain every little component because there's a crazy amount of stuff there are libraries full of how to understand javascript but what I want you to do is, as a Rails developer I want to give you the information you'll need in order to take it and to be able to build your own javascript functionality into your apps. And so what I want to do here is kind of break down exactly what's happening. So what we're looking for are these components on the page? If you noticed that is one of the main things we've done. We've looked for comments. We've looked at how we can add on to our list of comments and now we're looking at the process of creating a new comment and you're about to see how we're going to grab the value. So after we have access to $this we're going to store it in this variable called textarea. And next, we're going to just kind of do some housekeeping. So we're going to say...

if $.trim(textarea.val()).length > 1

if $.trim and then textarea.val. Now notice that .val that's exactly what we did in the javascript console. So we're essentially saying if this value is here and it actually has some content and then we're going to say .length is > than 1, then we want to perform these actions. The trim method is a jquery method that is going to take out any excess whitespace so in other words what it's going to look to do is if someone comes in here and instead of doing letters or characters they just type a bunch of spaces then it's going to just pull that out and it's going to ignore it. So that's just some data validation. So now what we're going to do is we're going to start to wire this up with our app. So with our global chat method here, I'm going to say...

App.global_chat.send_comment textarea.val()
comments.data('blog-id')
textarea.val('')

App.global_chat.send_comment and we're going to pass this, the textarea.val So the value for the text area. And now we'll say comments.data blog-id and then textarea.val and pass that in. Essentially what we're doing is we're saying I want you to send the comment which is our function here(send_comment) and I'm passing in textarea.val with the blog-id and then I'm setting the textarea to an empty string. If we didn't do this what would happen is a user would type their comment in, hit submit everything would work but it wouldn't wipe the textarea clean. And so it would be very confusing. It would almost look like it didn't work. Imagine being on Facebook and typing your status update, hitting submit it pops up but then all of your content stays in the form that would be kind of confusing. So we're going to clear that out.

And now we're going to take the event which is remember stored in this e variable and we're going to say...

e.preventDefault()
return false

e.preventDefault and then return false. What this means is remember how I was talking about how by default, what rails and any kind of web application is going to do is when you try to submit a form it's going to try to reload and go to a new page. That's the action that's how HTTP forms work. But what we want is to actually prevent that. And that's what the prevent default method does is it says instead of doing what you would normally do on the submit action. I want you to not change pages I want you to stay here and I will take care of the rest. I'm going to handle the data flow. So that is that. Now we still have a ton more we have to do before this can be fully implemented and live we have to wire up what we did here with our ActionCable and everything like that. And so we're going to stop the guide right now and take a little break. The one thing I do want to give you as encouragement I know this was a lot of code writing and it is you know, not as clean looking as Ruby or Rails code but don't let that scare you away. This is actually the most code we're going to write for the rest of the section. So be encouraged by that. Let's open this up and type git status. It looks like we only changed two items which is good. Those are the two we knew about. git commit -m " implemented jquery functions for actioncable comment feature" and let's push this up to the branch of actioncable. And in the next guide, we're going to start setting up our channel.

Resources