Ruby on Rails #59 Hotwire Turbo Streams CRUD

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
so today we are going to build a basic application using hot fire and more notably using turbo and more notably using turbo streams so i think streams are actually the coolest and most powerful feature in turbo now uh let's uh start with creating a new rail 7 application yes as you see i'm running rail 7 alpha and ruby 3. so i will say rails new let's say turbo app and database will be postgrad sql okay let's create the application and you see it's from input maps installed nice and also turbo install stimulus install so i don't have to bother about the installation of turbo and the stimulus that's also good and you see it's also generated a dummy stimulus controller anyway let's navigate to the application as i'm running on cloud9 i will have an error if i don't go to development.orgb and say config.hosts equals nil okay now i can say rails db great and start the application rails s i'll go to preview okay so the application is running looks cool now i will say get the add oh so let's say git initialize tables get at all hit commit main trade app okay now let's uh actually create the uh scaffold i will say rails generate scuffle message and a message will have a body for example so body text okay and let's run this command now i will go to our roots file and say that we'll have a root pass to messages index okay let's start the server okay run the pending migrations and we are on messages index and it is also the root path so i can go to create a new message create it now as you see i can create it with an empty body so i will add some basic locations i will go to app models message validates uh body presence true now let's try once again go into edit okay so it has to be present looks good and let's save our changes so give status hit add all hit comment main scaffold messages okay looks good now you see the application is looking well not really beautiful because it doesn't have any kind of css styling by default so to fix this i will just add the simple css css framework so let me run add this command to our layouts going to use layout application html adding it refreshing and yeah looks a bit better so okay now we are looking at our messages index page now this is a bit misleading let's go to the messages page messages index okay it is message yes i don't know why the scaffold generator didn't pick it up but it is messages and we have one message displayed and first of all we are going to make it so that we can add messages without page refresh so how can we do this well we are going to add a form first of all so we will display the form to add a message on the index page let's do this i will say equals render partial messages form and locales will be message message dot new and closing the braces and let's see if it is done okay so we have a field for body i can press create message if it doesn't work i am redirected to the edit page with the and notice that the body can be blank if i add a message successfully i'm redirected to the message now i will override these two behaviors with the our turbo so first of all what do i want to do if a message is successfully created then i will re-render this form here and if i have an error so if i try to create a message without any text for example this arrow is going to also be rendered here inside the messages index page and i'm going to easily do it with the turbo so i'm going to go to our controllers messages controller and you see we can respond with the format named turbo stream so here we have format html format json by default in a scaffold but we can also say format dot turbo stream now i will put it in at do block so if we go to the turbo handbook uh we will have examples of responding with format turbostream and we are going to render something inside anyway let's try to do it on our own i will say from a turbo stream i will say render [Music] google stream and next i will say turbo stream dot update and we need to update something well to point over a turbo stream is to update uh some kind of element some kind of html element with an id on a page so i will say element id with some kind of html or with some kind of partial locales so they'll have an element here let's just have it element id for now then we'll pass in the partial that we're going to send so the partial is going to be messages form and what are the locales going to be so locales are going to be if they save the message then we want to send a new message form it will be message equals message dot new okay and now this element id now let's uh give an id to this partial right here we are rendering a past shell messages form and we want it to be replaced with adorable stream so turbo stream is going to send the html of this partial with this locales into our html view for index and it's going to replace this now it must replace some kind of element id so let's give it an id i will say div id new message i will wrap this all into a div let me just refresh the page i'm going to messages i will go to inspect element and [Music] where is it you see i've wrapped it into this id new message and now i will go to our messages controller and here in this turbostream.update i'm going to say update the html element on the page that is sent to with a partial messages form and these locales so let's see this in action now i'm uh well i can refresh or i don't actually have to i'm going to create a message and you see it has disappeared now what has happened if i go to the logs i will see that a message has actually been created so if i refresh the message will be added to the list but this form basically gets re-rendered so only this part of the html page gets re-rendered i might be able to see the somewhere in the network i guess let me once again add something and you see i get this messages and i get this turbostream action update target new message and template is going to be the form so the messages form with the correct locales so you see a toolbar stream sends this [Music] html with us durable stream action update right into this place and what we've done we've re-rendered the form we've rendered the form with the the locales message message new if we have saved the message so if it was saved correctly but what if i press create message and there is no content i press create message and you see i just get body can't be blind so what do i get i get this render new status unprocessable entry and what i want to get i want to actually have this form re-rendered with the locales and message is going to be the message that we are working on at the moment and they're not going to have any page refresh so you see before redirect to the new action and i don't want to be redirected so i'm going to just copy this format to the stream [Music] into the else statement and i'm going to say so turbo stream update new message partial messages form and locales and message is going to be then message that was rendered invalid so it is going to be this message add message okay let me actually also beautify this a bit so that it is also more readable okay just like it and now i will once again try to create a message so i press create message and you see there was no full page refresh i sent a request to the server the server went to the create action it evaluated the message it understood that it cannot save the message and it sent adorable stream with the messages form to this target new message and with the locales with this current message that we've broken with and once again i will refresh i will go to inspect element and go to network i press create message i go to messages and here you see i get the this html the form and i have this errors rendered so body can be blank so if i go to the form messages form you see this html was rendered with the correct the error message so this is the basic principle of how of how turbo strings work now let's actually save our changes we've done already one small theme we can create a message with the form been re-rendered so git app all now what did it do in application html okay i just added the style sheets so git commit name ring render form event rating message okay and now let's go back to our application so it is far from been complete you see i will try to add a new message like hello world and you see it is not added to the list so why is it not added to the list because i need to refresh the page but it's not the approach that we want to have we are going to have turbo actually send messages directly into this page it's going to inject these messages on top on the bottom of the list so first of all let's actually just add some ordering to our messages i will go to our matches controller and go to the index action let's say messages dot order created at the sending so the newest ones are going to be on top okay and now going to the index page we have an id messages already generated by a scaffold and here we are rendering our messages okay and everything that we are going to do now is when a message is created we are going to have another turbo stream that will add the new message uh to this id so how is it going to work i'm just going to copy this i'll put a comma so that the syntax works and you see here i had update so update is kind of replacing one element with another but keeping the same id and here i'm going to update it with the partial messages index messages message so it's going to be this partial the actual message content that we have sent partial messages message and locales is going to be this message so i will say at message locales at message so what am i doing here oh actually not update but we are going to say prepend now if we go to the turbo handbook it will be said that there are a lot of different actions so there is append there is prepend there is replace update and so on so we'll come to the other ones later anyway we say double stream prepend meaning add on top of the list the list is going to be messages whether i have this messages from i have it from index id messages okay so add on top of this id it will be added somewhere here and we're going to send a special message with locals of this message that has just been created now again i can try and create the end you message press create and you see actually turbo did two things so it uh updated this form and it added a message on top of the messages list so works fantastic doesn't it now what if we had to stream dot append let's say topostrom.append as we have here action band so append will basically add an element to the bottom of the list let's just see how it works i will say i am appending create and you see it was added to the bottom of the list and you decide what you want to use based on your particular application needs so i usually use prepend more often anyway we are running two turbo actions at the same time from the same uh great action so again i can go to the network i'm going to inspect element let's see network i say hello world create message and if i look here you see the turbostream action is update and also somewhere there must be that we are sending the second turbo stream to append autoprepend yeah here it is so here is the second drupal stream action prepend and here is the message partial so you see in this uh from this controller and we send the two different uh things that we want to replace we replace two different uh divs with ideas so kind of dom ids here's one and here is the second and looks cool again if i just press create message we get the address without refreshing the page so i think it looks really great now let's uh save our changes so get status add all git commit main add messages to the list okay looks great and what if we want to delete a message from the list well how will it work let's see i would do maybe i want to add a delete button so let's go and see that we already have a delete button inside the template so the show template we have this button to destroy message let's copy it and add it to our message right here so here we have a link to show and we'll also have a link to destroy now i will update the locale so message path message met method delete looks good okay now what will happen if i just press delete if i press delete you see we have a page refresh so i press destroy once again and well these are all page refreshes now if you want to be certain i can just add a timer to our application html.erb so i would say something like uh equals time dot zone dot now okay so i press destroy and you see the time updates so we are actually having a page refresh at the moment and uh to do it without a page refresh we would want to do it with through both so turbo stream would have an action of uh delete i guess of remove and it would find an element with an id and remove it from the html that we have rendered from so from this html index page okay now let's add a few messages and we will go to our messages controller to the destroy action and here we're going to also respond to format toggle string so format dot turbo stream and we can say render turbo stream and double stream dot remove and we will say add message now by saying add message here it's uh where do we know that this is going to be this message well if we look at the html i go to inspect element you see uh each message has a unique id here in the html why does each message have a unique id because in the default scaffold generator you see we have this dom id message and the what this dom id thing does it creates an id like message and the id of this message so each message in our list has a unique id and this is really great and out of the box and if i go to our messages controller we have this remove message and how does rails know that we are removing the message with this id why don't we say something like [Music] a message and in braces it would have message.id well both things would work but turbo just knows that we would want to use this message here dom id so we can just have add message but if you added message underscore message id then it would also work let's uh yeah we can actually check both just in case so i will have add message here and let's see so when i press the destroy button i expect the no page refresh because we will respond to the format of turbo stream and i expect the etubo stream to remove this message from the message list so i will refresh let's open network just to see if there are any changes let's see if we have a page refresh so pay attention at the time and i press destroy and you see there is no page refresh but elements are being removed from the list if i refresh the page you see the elements totally deleted so it works deleting elements this way it works now you see without a page refresh we can add messages we can destroy messages they can render errors when creating the messages so it works well fantastically and we then tried a single additional line of javascript now let's just try this other option for this id so just generating well the id in this way just in case so i will press destroy and you see it works the same way so you can use both but the this one is more explicit and this one is better looking so anyway it is working well and let us save our changes get status get the add all now what is the change inside the application okay we added the time now hit comment main remove messages and valve works perfectly okay now what if we want to go a step further and do something more complex what if we want to actually edit messages without a page refresh now the perfect candidate for the job would be to use turbo frames but now we are going to accomplish this thing with turbo streams so we would do want to have an edit button first of all we want to be able to edit each message so i'm going to go to the message partial and going to add a link to edit i'm going to copy from here so edit this message okay let's refresh i will update the locale okay so we have the button to edit and if i press edit we are directed to a new page now how can they make it not redirect us to a new page how can we about render turbo stream let's uh just go back to the list where am i now so going back to messages okay uh we are going to respond with the format of turbo stream on the edit action so going to the messages controller edit action and let's say respond to format stream and and and well inside this format of a stream we will say render tuba stream superstream dot update and we're going to update this message that the partial uh messages message and the locales are going to be a message will be the message that we already have so message now updating the syntax okay so we are responding with turbostream now i don't like writing these long lines i don't better say do so that it doesn't look that long and put an end statement just like this okay so we want to respond with the format of turbo stream and replace the message with the edit form oh yeah not for the message but with the form so partial messages form locales message so we want to be able to render the form with the content of this message now if i press edit this message what i got i get action controller unknown format because by the whole design of turbo streams and turbo frames so turbo streams can respond to any request except a get request so the students can respond to fetch post destroy whatever and the turbo frames can respond only to get requests so streams do anything except forget and frames only to get and now we are going to kind of play a work around so we want to accomplish this particular thing using dual streams so and two streams cannot respond to a get request and this edit is a get request so if i go to roots edit message pause you see it is a get request so i'm going to say that it should also respond to for example post yeah for example post let's uh go to our roots and here we have resources messages i will say do then i will say member do because we are going to have an id and we will say post edit so it's going to also give us a post request to edit now if i refresh edit message path and you see it is now a post request now again i'm saying this is a bit hacky and unusual but i'm just showing how you can overcome some natural barriers and do things with trouble strings so they're going to respond with post now going back i will refresh i'll press edit message okay and it still says unknown format now what am i doing wrong it says unknown format because possibly i am going with a link to i should actually say method post in this link so in edit message i will add method post now going back refreshing pressing edit message it still doesn't work it is because we are not using rails ugs anymore and rails ugs is what was given our links to a possibility to use something like method post or method delete so we are going to have to use a button tool i'm going to add a button to edit this message now i will refresh so we have button to edit message let's press edit okay this is still not working but it's not working because i was editing the wrong template so you see i'm in the show view and i want to do it in the partial okay so anyway going to the partial actually we will not need to show view i will remove it just for us not to bother about it again okay and here in this uh link to edit message will be replaced with this button to edit message and now this method post convert idle refresh okay i will say message and here we have a button to destroy and to edit now i will press edit and you see it was re-rendered so we have rendered the form now i can go to the other message and you see it also renders the form for the other message so seems to be kind of working but if we update something so i will say hello update message what happened there was a page refresh so you see we have this notification the time has changed and the other form was removed and we are now going to do it without page refresh so i will go to our messages controller i will copy this and i will go to our update action and we are going to also respond with formative stream in the successful case and not in the successful case so first of all i will say the stream update the message partial is going to be message message the locales are going to be the message and if it doesn't manage to update so if there are errors we should render the partial they should render that form so i will do the same but render form okay so let's see if it works now here's the time i go and press edit message hello world i will also open editing the second message hello i'll press update you see it was updated i pressed update on the other and there was no page refresh now i can refresh the page and you see well all the changes are persistent so wow it works we've managed to edit our messages also using turbo streams without a single page refresh really amazing in my opinion so actually we did quite all the work and did one thing that can seem a bit hacky so we had this uh get method to edit a message but we replaced it with a post so it works now let's save our changes get status hit add all give comic main and what did we do we can edit messages okay looks good and going even further to the next level what if we want to see an updated quantity of messages so we will see how many messages we have on the page well usually i would just go to our index page i would have messages i would have equals message account for example i refresh and you see i'm adding new messages but the count doesn't increase until i refresh the page and we can do it also with turbo so in vodka it says can be does the message count change if we destroy a message or if we add a new message well we are going to add a few more turbo actions so i'm going to go to our messages controller enter the create action and in case of a successful message save i'm going to also say that we want to replace this particular count with a new counter so i will say to the stream dot update then we will need some kind of id i will say message counter and we don't need a partial we don't need locales we will just stream some html so i will say html and inside i will say something for example like inbox.com and now i will close the braces and put a coma here and it might work then i add this id so i'm going to index page and here i will put this into a div id i will say diff id equals message counter just like this i refresh now you see this on a new line so i will use spam instead of div refresh okay messages five now i add some message and i get an error why do i get an error okay because i use the word in inbox it doesn't matter press messages count again and you see the counter is updated and i didn't have to create any html template for this so i don't have to render an html template i can just run some html let's actually try doing the same vote without these braces let's just say html message count don't work or not i don't know i try and yeah it works even simpler even better fantastic don't work without the verb html let's bend the line so and it's working amazing okay looks good and now let's add the same action in case we delete a message so you see now when we increment the count it increases but when we destroy it doesn't increase only when i reload the page so let's go to our destroy action here we have format toolbar stream and i will change the syntax i will say do and then run the toolbar stream i will add these braces so that we can run the multiple streams to the stream remove message and the stream update the message counter and i'll put a comma between and it should kind of verb so let's try i'm adding a message i press destroy and it works i try to edit the message hello and it's working amazing so now you see we also update the message counter it looks like clockwork fantastic get status get add all you commit main update messages counter fantastic now is there anything else that we can do right here actually you see when they add message or something they don't have any kind of flash notification that they've done it so what if you want to have some kind of notifications on the same page without the page refresh that some action has happened well this is also an interesting case and there's actually a quite easy way we can solve it easy and elegant so let's uh just go to this page and somewhere on this page yeah we already actually have by default this id notice okay and let's try to see how it works so we have this i didn't notice it is in a bit bag okay so we want to update this notice with the something else now by default we have nothing in this notice it is empty and uh yeah we are going to replace this notice with something else let's uh go to our messages controller and say when we create a message we will also update the notice so this notice with something let's say message created we'll put a comma and i'm now refreshing great and you see we have this message created you can also add an id or something so message message dot id created okay now i'm refreshing and you see we have the message id also visible and we can add this kind of to the stream to all other actions so go into the update action we will also have rendered stream we are going to render two streams so update this partial and we will also update the notice and the notice will be updated with message updated let's see how it works i will press create message i will edit this message and you see we have this updated i go and edit another message and you see it was updated once again and we can do the same for our destroy action so we're going to our destroy action we will do string update notice with message deleted let's see i delete a message and you see we have this message deleted notification okay so it's working fantastic let's again save our changes get stables add all main and basic flash okay looks cool and now what have we done in this uh small basic application we've made it so that we can use in just one page so it is a single page application spa we can create messages you see there is no page refresh we can create messages the county has been updated the flash has been updated we can edit messages we can edit multiple messages at the same time we can destroy messages and this all happened without any javascript and without any page refreshes and for this we are just leveraging the one simple functionality of turbo the turbo streams so well that's it for today thanks for being with me and have fun coding
Info
Channel: SupeRails
Views: 762
Rating: undefined out of 5
Keywords: ruby, rails, ruby on rails, tutorial, programming
Id: csvaYIaBYpw
Channel Id: undefined
Length: 40min 56sec (2456 seconds)
Published: Fri Nov 12 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.