Like button with Ruby on Rails

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey what's up welcome back we're working on building out a blog application we've already added a bunch of posts and comments today we're going to talk about adding likes so we're going to start out with really basic how do you add a like button and an unlike button and then we'll uh we'll improve that in another episode and we'll talk we'll start talking about polymorphic associations but today we're just going to go through the simple steps of adding likes to your blog posts so in order to keep track of someone liking or unliking a blog post this is like i guess it was you know originally popularized by facebook when they first started rolling out posts with likes on them well if you think about the data that we need to track we need to have reference to the current user who's liking the thing and then we also need to have reference to the object that's being liked so in this case we're going to start off with a post so let's create a new model here so we're going to say rails g model like and it's going to reference the user references so we're going to have a foreign key to the user id and then we're also going to have a foreign key to the post model so we have a post and we'll have our like also reference the post so one thing that we want to prevent though is a user from liking the same post multiple times so we're going to do is open up this data migration we've got these two these two foreign keys already so that's great but what we want to do now is we're going to add an index that enforces the uniqueness of the combination of the user id and the post id so let me show you what i mean so add index here to the likes table for user it's going to be user id and post id unique true and the reason we want to do this is so that in the database at the database level we are enforcing a uniqueness constraint on there being a single like at most a single like between the user and a given post so a user can't like the same post multiple times all right i think this should work let's see rails db migrate that unique used to be unique there was like a name change recently so i i can't remember if that's exactly it okay so it looks like that worked so now if we say like for instance let's actually open up our user model and say that this now has many likes and our post model post rb post has many uh likes then we'll open up uh the rails console and just play around and see if we are able to create a like multiple times for the same uh for the same post from the same user so we say u is user.first and then we see p is post.last and we say like like.create user is you and post is p that should create the like because that's the first one now if we try to do it again it should fail and it does because now we have a duplicate key value violates a unique constraint for index likes blah blah so this active record not unique exception is being raised at the database layer so we're now like preventing multiple likes at the database layer but we can also go into the model into the like model and say that we have like a uniqueness constraint at this level too so here what we can do is we can add a validation so we can say validates uh user uniqueness in the scope of the post but we actually want to use the id forms so that we don't have to make any any underlying requests we're going to say we're going to validate that the user id is unique as long as we have the same post id so this should apply a sort of model layer associate validation for us so now if we again reload rails console we should have a brand new uniqueness validation error that we see when we try to create uh so we have the first user p equals post.last and then if we try to create another like now we're seeing this rollback but we're not seeing the database level exception instead if we were to say like uh if we were to say like is equal to like.new and then like.valid and that's going to give us back false and now we can look at the like.errors.full messages.2 sentence and that should give us back user has already been taken we could we could technically sort of update this error message to say you can only like a post once but this is enough for now now let's create a likes controller that will be used to create and destroy those like objects we'll say rails rails g controller likes and this is going to be again the controller that receives post requests to create a like and delete request to destroy alike we'll go into our routes file and add a new resources for likes and we're going to say this is only going to be for create and destroy we'll go to the likes controller and we need to define create and we need to define destroy and when we go to create a like we need to pass in the id of the post and then we want to use the current user we want to look them up because they're authenticated and so we're going to we're going to create a new instance of a like here and we're going to build this again through the association so we're going to say current user.likes.new and we need to pass in some like params here which we'll define down at the bottom so we'll say this is private and we're going to define like params as params.require like dot permit host id because that's going to have just the id of the post so we know which post we're liking here now similar to comments we could have nested this underneath uh we could have nested this underneath the post resource and said like slash post slash like but later on when we make likes um polymorphically associatable or we use when we use a polymorphic association for likes later on so we can like lots of different things it'll be nice to have this in a separate controller so to minimize the changes when we make that update later i'm just starting off with the likes controller that's constructed like this and so if we are not able to save the like uh we want to flash a notice that just contains the error message and then we ultimately want to redirect to at like dot post again we could probably do uh you know params like post id or something instead of redirecting directly to the post here because maybe the post doesn't exist or something but this is probably fine for now all right so now that we have a controller action for to create let's also make one for destroy just while we're in here so we'll say at like is equal to uh like or current currentuser.likes.find params id we'll expect that we're gonna sort of like send a destroy request to something like uh like slash 10 or something and that will be a post request with the method set up so that it's a delete http request and it will hit this route we'll find the like scoped to the current user so no user can delete someone else's likes and then we're going to say post is at like that post just so we have reference to the the post before we destroy it i think we'll still have reference even after it's deleted but i like to keep track of it like this and then we'll say at like dot destroy and we'll redirect to uh post okay so now we've got our two controller actions here for creating and destroying likes let's jump into the uh the post show and talk about how we might actually add a button here so let's let's start super simply and because we're sending a post request technically we need some sort of form right and so the form will just be a very very small form and on the page it'll show up as just a single button and there are tools inside of rails called button2 and we'll look at that in just a minute but first i wanted to implement this with just a standard form so we're going to say this is going to send a post request to slash likes and we've got our authenticity token in here the button is going to show like and we also need to include an input that's hidden and that includes the the uh params for the post id so we say like post id and its value is going to be the id of the post that we're looking at currently so at post.id all right so this is the form that we want to use to actually send a post request back to the server with reference to the post id and because we're logged in we know what the who the current user is and we know you know the the post now that they're they're liking so we can create that like object start up my server we are back on the posts show page and now we have this like button so let's right click this and inspect and let's take a look so we've got a like button and we can click on like and it looks like that may have worked because we should be redirected correctly back to this post 11 and if we look in the server log we can see the uh post request coming in here for slash likes and we've got the post id that's post id 11 oops and what else did it do here for us um yep so it did create so we inserted into likes for the user id and we actually did create that um that like so let's actually jump into rails console and take a look so if we look at the la the very last like the user id is the currently logged in user and the post was 11. so if we try to click this again we expect to see an error so we clicked it again and we see user has already been taken again that's the error message that's coming back from from the flash notice and that is the error that happens when we try to create a second like for the same post so what we want to do now is we actually want to hide that like button if the user has already liked this post so we want to hide the like button so let's do that here we'll just say like you know if current user dot likes dot find buy post at post if it's nil then we'll show the button otherwise we actually want to like have some unlike situation but we'll refresh the page here okay so now we can just see we can see unlike but we need to make that also a button that can send the destroy request so while we're here if we just say like.last.destroy so we'll remove that last one from the database and refresh the page now we see like and if we click on like again we see this unlike thing so that seems to be working it's showing the the button that we would expect so now let's actually implement the form for unliking the post or removing our like from the post so i'm going to use uh this form again now this time the form action is going to be for that specific like so it needs to go directly to that specific like so we're going to say like path for the like and we need to grab reference to that so up here what i'm going to do is say like is equal to current user.likes.find by post at post just so that we can reuse this in a couple different places so here instead of checking if this is nil we'll check if like is nil and then down here we will say we're going to pass the like in just like so and then we should say this is uh un like now in order to make this form submit not a post request but a delete request we actually need to add another hidden input field this is just how rails works so we're going to add another input that's hidden that has the name is equal to underscore method and the value here is going to be delete that will make it so that rails interprets this post request as a delete request this is kind of the trick here when you're working with rails and yeah you want to send delete requests all right so we'll go back over to our application refresh the page and we've got an error here i think this should be equals um likes path undefined method like path for action view base okay so i think routes did we have create and destroy yes oh okay so i misspelled i said resource instead of resources so this should have been plural resources so that is how we get all seven routes if we do resource then we only get one route okay so if i refresh the page now and i look at like okay great so now my destroy path does have the id there so i should be good to go now so that mistake should be fixed okay so now we've got an unlike button here and again if we inspect that we've got so it's going to send a post request with this hidden method delete which is going to make it a delete request so let's try our unlike all right so now we've got a button where we can like it or we can unlike it that's pretty cool uh maybe one other thing we might want to add is how many likes there are so we could add sort of a counter blog show or post show here maybe we will just add a quick counter here that's like um at post.likes.count and in in practice we might want to use a counter cache here and we'll talk about that in a bit so um and we'll say likes or something um cool all right so this is now technically working uh we've got one like we've got two likes one like two likes great so that is all working as expected now let's do um a quick refactoring to use the button2 form helper and so button2 is right here this is the documentation for it it is a method that accepts several different arguments and instead of having to write your form out like this it can you can use button two that will and it will automatically build the form for you so here what we want to say is button we're going to say percent equals button two and the very first argument is going to be what you want the button to say so in this case like the second argument is where you want the button's request to go in this case we can use likes path and then there's several different options that you can pass along the way so here we want to send some we want to send some form data so in addition to those first options we want to send the method as post eventually so method post that's usually at the end at the very end and then we also want to send some actual hidden params so we're going to send some params here this is going to be the hash is it's a hash type object that has the parameters that are going to be rendered into hidden fields within the form so again recall that here on this button we have these hidden fields so this hidden field here has like and that's a post id so on our button 2 we want to say params like and post id is at post dot id and so what we're doing right now is we're just basically doing the same exact thing as implementing the form with html but showing how to do it with a form helper so now we have two like buttons if we look at we can look at each of them and just take a look and see if they're actually rendering out what we want so here the form class is button two and we can see that it's correctly going to send a post request to slash likes and that it's correctly got this hidden input field for post id so if we click on that that worked as expected so we can do the same thing for unlike unlike and instead of likes path we're going to like path passing in like we don't need to pass the post id anymore because we have that and then instead of the method being post we want the method to be delete and i think that should work just as expected so now if we refresh the page we've got like and unlike and yeah so here we have the hidden field for delete and oh no so this is the button too this is button two here so we've got our hidden yeah again our hidden field with method delete and our authenticity token etc etc so now um both buttons work totally fine now this is going to be a choice that you're going to make when when implementing your own solution would you rather use the the form helper that is this sort of erb method for constructing this it is fewer lines that's for sure but what i have found personally is that it's much more challenging to sort of style and make it do exactly what you want and so i tend to prefer using the full form and i just have a i have a snippet in my editor so it's really quick to build out the form um and then i know for sure what hidden fields are being added and exactly what their names are instead of having to sort of like mess around with this this api up here so that's totally a choice for you but um this is my my preference is just to write out all the html so i'm going to remove those button twos and then yeah i think we'll call it good there in the next episode we'll talk about how do we take this concept of liking an object and make it more generalized so that we can like other objects great thanks so much for watching and we'll see in the next one [Music]
Info
Channel: CJ Avilla
Views: 716
Rating: undefined out of 5
Keywords: cjav_dev, web development tutorials, web development for beginners, vim, ruby, rails, javascript
Id: bD--WOyQkug
Channel Id: undefined
Length: 17min 57sec (1077 seconds)
Published: Mon Aug 30 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.