How to use Hotwire in Rails

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hey guys this episode we're going to be talking about hotwire.js and giving you an introduction on how to use it in your rails applications now hotwire is a new um approach to building reactive applications that are more server side and html over the wire so we're going to be using this to build a twitter clone just like everybody does in their examples so we can dive in by installing hot wire for rails so first things first is you want to install the hot wire rails gem so you can go into your application and run bundle add hot wire rails this is going to install turbo rails and stimulus rails now stimulus rails install stimulus js in your asset pipeline so you can write your controllers without babble and webpack and all that stuff and then turbo rails is basically the new version of turbo lynx it actually supports forms and more than just links like hrefs for get requests so that's why it's called turbo instead of just turbo links like it used to be it's pretty much a replacement for that with more functionality so you use that in place of turbo links so now that that's installed we want to run rails hotwire install to add all of that insulation config to our application so you'll see that they install your app assets javascripts your asset pipeline folder gets your stimulus controllers now and they configure redis for you as well for the action cable websockets so let's run our rail server and take a look at our application we have a scaffold for tweets tweets have a body and they have a likes count and retweets count very simple and whenever we create one of these they just get created and listed here in this list so we're not doing anything with that right now this is just a standard rails uh scaffold and we've got views for that so we have the form it submits as a post request and then redirects back to this page and re-renders it pretty straightforward but to use hotwire we can start setting up frames and other things in our app and the first thing that i want to do is go into our model we can add broadcasting to our model so that when it is created updated or destroyed we can actually send those changes to the browser from the back end so what we can do here is say after create commit we can broadcast append to some stream and if we call our stream tweets we can have this broadcasted to all users and they will see that new tweet so let's do prepend to tweets so it will show up at the very top here so by saying tweets here we actually need to create a frame on the page that has the same name so if we go into our index.html.erb we can add a turbo frame tag with the name of tweets and we can wrap our tweets around that so let's refresh our page we'll see that there are no differences here visually but we do have that turbo frame with the id of tweets so whatever we pass in is passed to dom id um and if it's a regular string it just adds that as the id here now this almost works but we have one last thing to do to wire the front end to the back end and that is adding a turbo stream from tweets tag what this is going to do is actually set up a line of code in your html that says hey javascript go and stream from the tweets stream so it's actually going to tell the action cable channel to stream from that then our tweet.rb is going to broadcast to the tweets channel and it's going to then uh prepend that to the target of tweets so now if we jump back to the browser and we refresh the page what we'll see here is the turbo cable stream source tag on the page and this is what's going to be sent over action cable and it will start streaming from the tweets stream so now if we open up a rails terminal we can go into the console and say tweet.create body is hello world and we'll see that it gets pre-pended automatically on the page so this is really awesome and allows us to push updates to the front end and we can navigate between pages and that stream tag is going to be monitored and start the stream and close the stream whenever you move away from that on the page so we can go into our tweet and we can say after update commit we want to broadcast a replace event and that is going to the tweet stream and we can do the same after a destroy and we will broadcast a remove in that case so this is going to take the individual tweet and send it across and make the action that this name is for so replace prepend or remove so now we can go into our terminal and run tweet.last.destroy and we should see that that is broadcast across in the browser um but it is not and the reason for that is because this is actually going to look for a target of tweet six and you can take a look at the commands that are sent over they're actually little html snippets with the turbo stream action and you'll see that the target is tweet six and if we were to do the same thing for updating we're not going to get that to work and update these in real time because we actually need to wrap each one of those tweets in a turbo links frame as well so we have the turbo links frame here for all of the tweets and that's where we know to insert the tweets but we can also do a turbo lengths frame around the individual tweet itself so what we'll do is we'll say turbo frame tag for the tweet and we will wrap that now what we can do here is uh to use the dom id for the tweet so that when we look at these we will see the dom id of tweet one tweet two and that's exactly what it was looking for in the terminal when we ran that broadcast so there are several little things you do have to keep track of and if you don't use a dom id here what you'll see is the actual tweet memory address and stuff like you do in inspect and that isn't what you want so you're going to want to make sure you do a dom id there and that is going to update your page so that now we can call a destroy and we can do update here and say body is hello go rails and that's going to publish those changes and replace the element on the page or destroy it and remove it and that is really awesome so now we can pipe these changes anytime something happens in our model layer so that the browser is updated reactively which is really really awesome so the frames so far are pretty useful we have some basic stuff going on where we have a frame around all of the tweets we have a frame around every individual tweet and we can make actions across those so now let's talk about handling tweets in the form so we have the form here where we can wrap this with a turbo frame tag as well and we'll call this tweet form and this is where frames get to be pretty interesting so far we've just used them to update and replace and remove things and take actions against them it's very familiar if you've ever used cable ready you can target elements and make the same changes to them but with our form this is going to show you something unique which is that the forms are or the frames are actually encapsulating like an iframe does so let's run create tweet here with nothing in there we have a validation in the model so let me pull that up real quick go into tweet.rb we have validates body presence is true and that is going to give you an error message whenever um your tweet is created without a body so we're not getting anything right now but that frame is actually doing some magic in around this form so let's take a look at our rails logs here let me pull this out a little bit for you and what you'll see is when we actually do create tweet here we're going to get a post tweets and it does post but we're going to get a completed okay in 23 milliseconds but the type of request was a turbo stream request so turbo is actually taking your forms and submitting them for you very similar to how you would do with remote is true in rails ujs but turbo is actually going to do that stuff for you so you don't want to use rails ugs to submit forms remote is true anymore so that is one big difference that you will need to do as you go through here and we can now go into our controller and take a look at the tweets controller.rb and address this nothingness happening when we create a tweet we can click that a million times and it's gonna do the post but nothing's gonna happen on our front end so let's walk through what happens when we run create so normally we have html and possibly json or javascript responses but turbo and hotwire are going to add a format dot turbo stream option here that you can use and what we want to do is say when the tweet is created but it's not valid we actually want to replace this form on the page with the form partial and just pump that over and say hey replace the form with the one with errors and it's very easy to do that by using the turbo stream helpers in your controller so what we'll do is we'll say render turbo stream colon and we will say turbo stream dot replace and you'll notice that this is very similar to the broadcast replace in our model it's the same concept here it's generating that tag and sending it over the broadcast is actually sending that in a background job through your websockets or it can be but this is actually going to return this as a response to your http request so you're using ajax to submit the form and you're going to respond with some html and that's going to be a turbo stream tag for replacing so what we'll say is we'll say at tweet we want to render the partial tweets form and our locals here is tweet at tweet and we'll close that so this is going to render that partial and send a replacement to the browser but if we do that currently it doesn't know what to do with that partial and what we need is an id on our form tag and we can say dom id tweet and this is going to create a dom id called new tweet because it's a new tweet it's not an existing one we're not editing anything and that is going to fix our form so let's refresh and click create tweet and now we get the errors piped over and if we open up the rails logs you will see that when we do a post it's going to get an ok and it will get that tweet form rendered out there and so it can do this very quickly and if you want to take a look at what's happening in your browser go and submit a request here and you'll see tweets is made as an ajax request you'll see that with the fetch type there and it makes a post request and the response is a turbo stream tag and that says replace the new tweet target with this template and so it's very straightforward you're rendering the partial you're sending a command back and the command is actually just an html tag wrapper around your template so it's actually really really simple how this works it's not using json for any of this it is html over the wire and those commands are interpreted it sees the replace it knows what to do in the replace case and we'll go and replace this form with the new one so we can go into our controller here and take a look at what happens when it is successful so our code on the back end for the success case is just going to do an html or json response depending on your request type and that's kind of the special thing about um about turbo events when you are submitting a frame like this you are going to see that that actually worked and we didn't write a turbo stream format for this it's actually going to use the html response by default and if you have a turbo stream response to take precedence over that it will so what happens is when we submit a tweet it's going to make a ajax request and it's going to do the html response so if we look in our logs here we got a post and it redirects to slash tweets so what happens there is actually this is done in a frame so this is processed the redirect and the frame is processed separately so it's kind of fascinating because that's going to re-render the page but actually what happens is our turbo stream from the model broadcasts that new tweet and then prepends it so if we say prepend here what we will see happen in our html is that it will prepend that to the tweets turbo frame and we'll see that that just gets inserted and nothing else happens and that's because the redirect actually renders the html for the whole page again and then the frame is going to look for a matching frame in that response and then update the form field here so that's how this gets reset actually so it's taking that tweet form frame from the render again and replacing it so it's kind of fascinating the frames are able to navigate on their own and replace subsections of the content automatically for you so you can write full views like normal but it's only going to grab pieces of that as it goes so let's talk some more about frames if we were to go into our tweet individually and say link to edit for a tweet i know it's a crazy idea um you know god forbid would be able to edit our tweets but if we did this inside of our frame we can refresh the page and we'll see an edit link and this doesn't do anything and that's because it's inside of a turbo frame it will actually make a request for that so let's clear this out and you can see that request to edit and it will grab the html for that without a layout so it's automatically doing this without layouts for you and it's going to render the edit.html.erb now because there's no matching frame tag inside of there it's not going to do anything on our page it's going to basically get the response of all this html and do nothing with it so in order to make that work we're going to have a turbo frame tag here with the dom id of at tweet and we are going to wrap our form so this is going to replace now that tweet itself with the edit view but only the stuff inside of that turbo frame tag and you'll notice that our card body disappeared because that's not inside of that partial or this view and so we would need to add a div class card card body in order to make that still match so let's refresh and click edit now so this is what you were seeing in dhh's screencast the turboframes are making requests and it's basically treating it like its own little iframe almost so everything that happens inside of this is actually relevant related to this frame itself and doesn't modify the whole page so in order for us to add a cancel button inside of here we would add a link to and we will say cancel but instead of linking to say the tweets path like the root index we will actually link to the tweet itself and the reason for that is because the tweet show is going to be the one that's requested and then this needs to render a turbo frame tag for the tweet with the contents of the tweet so we can go into this view and we can take all this stuff or replace it with the turbo frame tag that renders at tweet and this will now be what's requested on a turbo stream link so now we can click edit and click cancel and it will go and undo what we just did visually but what it's doing is actually rendering the index rendering the partial for the tweet for every one of those then when you click edit it renders edit it takes the frame from the edit and replaces the frame on the page and then when you click cancel it actually makes a request to the show of the tweet and then replaces that frame as well so you'll notice that it does not include the edit back or the notice here it only includes the turbo frame tag contents so that's pretty fascinating how this works so now we can go through here we can get rid of our contents there we can click update tweet our errors happen in line we can cancel we can go back and all of that works as you would expect it to and you ended up building basically no unique stuff in your code here we don't really have anything that uh special editing a tweet links back to the tweet like normal all of these things do the exact thing that you would see them render in the html version so this is really a fascinating approach to see and it's kind of mind-bending to understand but if you inspect those requests that happen just keep in mind that if you're in a frame it's going to grab the frame from the response on the previous or on the request so the requests response needs to have a turbo frame otherwise it's not going to appear to do anything and the frame needs to match name-wise so in our case we're using the dom id for the tweet so this is pretty fascinating stuff so let's go and add resource like and resource retweet to our tweets and our routes and then we can go into our controllers and add a likes controller.rb class likes controller and here it's from applicationcontroller and on create we want to take and find the tweet so we'll say before action set tweet will grab the tweet as we normally would def set tweet at tweet equals tweet dot find params tweet id and here we will say increment the likes count and let's redirect to at tweet so this is where the real magic starts to show because you are going to click on the like button it is going to make a post request to create it's going to redirect to the tweet so it's going to render the tweet html version and that html is going to be what turbo grabs and replaces on the page this is where things get to be really awesome so now we go into our tweet tweet.html.erb and pull that up here and we can change our likes from just being text and we'll say button to like and we'll say tweet like path for the tweet and method is post and we can say likes uh tweet dot likes count inside of that and then we can do the same thing for retweets when that is ready so now we see the likes we can click that and it automatically works and all of the code for our controller is exactly the same as it would be for an http regular html request which is awesome this is what is really really neat so let's go and add a retweet controller retweets controller dot rb we'll paste this in and we'll have our retweets controller and this will increment the retweets count so that now needs to just get added here retweets and this is the retweets count with the tweet retweet path and we can delete this button here and we'll see likes and retweets are incrementing and that is just basically making a post request taking the response of that and replacing that tag because it's inside of a turbo frame so this dom id tweet is the one it's looking for in that response and because we render the tweet show it knows exactly what to do there so this is quite cool and my ordering's out of order but that tweet goes and drops to the bottom here so we're able to go and update those as needed so it's pretty awesome i love the way that this works it is quite a bit to wrap your head around because of these frames and the streams and broadcasting because it doesn't work very straightforward not quite as straightforward as something like stimulus reflex but it is way more powerful because of that you can create the stuff that can go and lazy load other pages and whatever and it can do all that just like regular html requests in your app so there is a lot of cool stuff that this does for you and it does feel a little bit like magic as dhh said so that's it for this episode i hope you enjoyed it and we will be doing a lot more on hot wire in the future but for now i will talk to you guys in the next one [Music] peace
Info
Channel: GoRails
Views: 24,938
Rating: undefined out of 5
Keywords: Ruby, Ruby on Rails, Rails, Javascript, HTML, CSS, Servers, Databases, Screencast, Tutorial, Rails 6, Action Text, Active Support, Action Mailbox, Webpacker, Active Storage, Active Record, rails testing, ruby on rails testing, ruby testing, devise, rails devise
Id: Qp6sxgjA-xY
Channel Id: undefined
Length: 24min 26sec (1466 seconds)
Published: Wed Dec 23 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.