Back to blogYouTube Video

Published August 9, 2025

continue building gocord

Can't play the video or having issues? Here's the direct link.

AI Summary

The developer continues building 'gocord,' a Discord clone, focusing on the implementation of server invitation and joining functionality. The session covers full-stack development, spanning the Go backend and the Electron-based React frontend.

Key Takeaways

  • Implemented a server invitation system that generates unique alphanumeric invite codes and stores them in a PostgreSQL database via GORM.
  • Developed the frontend UI for inviting friends, including a modal that displays the generated invite link.
  • Built the 'Join Server' functionality, allowing users to enter an invite code to be added to a server's member list.
  • Resolved several technical bugs, including issues with relative vs. absolute paths for server icons, database migration errors, and GORM association preloading to avoid foreign key constraint violations.

Description

gonna continue building gocord (the discord clone i'm building these days)

Transcript

Auto-generated transcript
Am I live? I think I'm live. Let me make sure real quick and then we'll do something productive. It's been a while since I streamed last. I think I haven't done this for like three days now. which sucks for consistency but you know what can you do okay perfect I'm live all right so what am I doing today well I guess we're gonna start with continuing to build this go-kart application that I started building. I haven't touched this code since the last stream. I've just been too lazy with this. So let me open up the backend as well and then we'll see where I left off because I have no idea. Close this. Open up the backend. There we go. And yeah. and this time i actually remember to turn on the database before i turn on the back end so yeah let's do that first okay yeah so this this is what we were building the last in the last stream we created this server create um handler and now we're gonna try and create all of these so let's see first of all obviously just need to run the database and the command is this wait what the hell I don't have the image oh wait I think it's start not run yeah there we go Okay, kind of a mishap over there but anyway now we wait for the database to start and then we run the backend and then the frontend and then we try to build all these things. I have no idea how I'm going to do this but we're gonna figure it out It can be that hard right So let try running the backend And yep it running Perfect So the database is running as well Perfect. Now let's run this. And let's see where we are right now. So again, in the last stream, we created all of this server creation functionality. I should probably test that out one more time. and then we can see what comes next after that. Mm-hmm. Takes a minute to load. There we go, and this is the Electron application. Okay, so it's not connecting. Why is it not connecting? No errors here. Let me refresh. Okay, what? Is it supposed to fail? I'm pretty sure I left this in a working condition. What the hell? On port 8000. Perfect. Now what's the problem? It is being forwarded correctly. Hmm. Well, this is not what I expected when I started the stream, but... Yeah, this is not working. Why is it not working? Hmm... Oh wait, wait. Wait a second. It's probably because the token expired, right? Yeah, the token expired. Okay, so we do obviously need to handle this. If the connection doesn't work, then we are probably logged out and we need to redirect to the login page. I'll build that later. For now, I guess I'll just log in with something. And there we go. and now it should be able to connect. There we go, perfect. So now it's actually working. And okay it unable to get the media for some reason Oh it trying to get it on localhost 3000 That the front end We need to get it from the back end So why is it doing that Let me see Where does it actually get that This should be in the front end code right So by the way I talking about these server icons It trying to get the images for these server icons and it failing because it trying to get them from localhost 3000 which is where our front-end is stored not the back-end the files the media files are going to be in the back-end which is in localhost 3000 so I need to use the absolute path over here instead of the relative path so to do that where exactly am i rendering this okay right here render server icon this should be it and yeah okay so I guess I can wrap this in backticks and just do something like this and also add the base URL here which should exist somewhere yeah there is okay and this is level 8000 slash this okay that should be fine now refresh again and see if that's correct and it is not correct let me see what am I getting this time oh it needs a slash okay that's an easy fix just add a slash over here and then let's see and there we go we're actually getting it now this one is still failing probably because the image doesn't even exist oh yeah it doesn't exist because there's two dots over here instead of one yeah there we go that's just the wrong path we don't need to worry about that because like I just created that while we were testing but yeah that's the server stuff and this is the messaging stuff nothing to worry about over here we can create a new server I guess we can call it I don't even know lonely groups I don't know add some dumb description for the server icon over here and I'll just use this some weird thumbnail for my video create it and there we go now there is no like this is still incomplete it supposed to refresh and take you to the new server and whatever so this is still incomplete but the server did get created and we can see that by just refreshing and there it is now we just open it up and it has no channels so we need to set that up as well and since it has no channels it's not displaying anything here so there's a lot of work to do on this app where do we get started so yeah I'm gonna start with all of these things and so we need to build server joins how do we build server joins well we need to be able to invite other people to the server and then they can join so to do this the first I guess we need to build the server invite function and then we can invite another user. So to do this let's create the invite invitation function first. Before that I'm gonna go over here and check out the server page and just make sure that it displays the channel list and everything. So to do that we can take this out and just do this and then do this lots of conditionals here just to satisfy typescript but it's fine and there we go so we have the server name and everything and we have an invite friends function here which we need to build still so we're gonna do that now how do you invite people I guess you need to first of all open up some morale or something to make this work right yeah we're gonna do that and how do we do that don't really need this stuff actually we do we do I guess the functionality is gonna come from this options parameter we need to have at the very least the option name and then some sort of a handler function that can like do all the operations related to this task or whatever so So how do we structure this? How do we build this? So we have all of these. I guess we just need to assign some sort of a handler to these now. Or we can assign a component to them. That would be best. We can assign some sort of a component to them. So I guess we can create a modal and then just use that. Yeah, I think we can just use that. I'm going to try something out over here. Let's see... We're gonna turn all of these into objects with a bunch of names and a bunch of handlers. So, let's see... The component can just be the... right now, it can just be the create server model. server model this is obviously the wrong one but i just want to like test that this does work and there we go and then this is going to be an object i guess we're gonna give it the name and if this gets clicked then we want to render it how do we render it um so i need to have some sort of a state over here i guess I guess we can create a new component for this server drop down option I guess we can just call this there we go and this can have some actually do we even need a new component for this maybe I'm just rushing this do we even need a new component can't I just do it all in this one I basically just need to like be able to create the like render the component right so and to do that we're gonna need state can you actually have state in like these inside of these objects like this I wonder if you can like because usually when you see state in react it's like this right you just have some like variables over here you don't really have a whole object or something so I wonder if we can do something like this and it not gonna fail on me or something Let just call this open state Let me just make sure that this is actually not completely, you know, bad or whatever. Oh, by the way, GPT-5 came out. I don't know if this is actually good or not. To be honest it just feels like regular GPD. Can you use react state inside objects like this? And let's see what it says. Yeah, see that's the problem. that is the problem right hmm I guess this is a good way to do it as well just creating a custom book but at this point I just want to like build the functionality and not like get bogged down by the details and stuff so this is just too much work right we're gonna remove this I'll just call this the uh invite state set invite state and just use state over here there we go now to actually use this we need to set the um so on click it should um where is it yeah i guess now we can use the open state over here right because i'm i'm declaring it up here so i should be able to like use it down here i think okay there we go and yeah something like this basically or actually like this i don't know why we need to do it as const but yeah i don't think we actually need to add a constant over here but yeah i think we i think that's all we need to do so now we can just do off dot open state number one the second function the second the the second item in the list which will be the actual function and we can set this to true and this is going to fail why is it going to fail okay because of that so it's the code is correct it's just the type error because lists I guess don't really have order in them so that's a bit of a problem what we can do instead of this is just use an object because objects have unique keys so it's not gonna you know give us any error like that so we're gonna have a get and set over here and that should be all we need remove this open state dot set and then we can add a function over here there we go and then we can actually just render the component I guess wait some sort of a modality I'll give it the open state which will just be the options own state I guess why is it giving me these okay there this needs to be inside this for loop over here and of course we can only render one component at a time so wrap this inside a fragment like this and then do off dot open state dot get and and op dot open straight dot set there we go now we just need to add some sort of content inside here i'll just create a heading that says invite friends there we go and yeah and also probably a good um good practice to have over here is something like a button that can you know just close the modals when we're done with this so let's just give it a background of 400 gray and text white and then I'll just call this call close or cancel and I think that it so now we can render this and just I I guess run this see what we get But actually we do need to add an onClick handler over here And this will just set the open state to false, right? So all we need to do is do op.openState.set to false. There we go. and this should only render when the open state is true right uh and and there we go because like otherwise we don't want the modality to render but actually do we i don't think we actually need that now that i think about it because the modality already uses this open state to render itself conditionally so i guess we don't need that probably but let's see we can refresh this and see what we get yeah okay perfect and okay nothing happened why did nothing happen let me just add that unique key so so we don't get some dumb error from that there we go uh why did this not get rendered that's the real question yeah it's not getting rendered it is it is definitely being set to true here that's for sure we can even do something with like showed it showed over here kind of just like logged the thing over here and then let's see yeah it's oh there we go that's weird so it didn't open before but now it does huh wait a second something weird is happening okay click click it but nothing happened if I click on this options menu then it happens that's so weird oh wait wait wait I got it I got it it's because it's because the these options only like get displayed when the the menu is open so yeah That's that's a problem. Oh I guess we need to actually render these models outside of this this open and conditional so out of here To another server options dot map We'll have the option will have the index And then actually just render the model over here You can give it a key as well because why not and yeah there we go now it should be fine I can refresh this again there we go so we have on our dial perfect and now we can just design this better I guess fix this that's why the button looks so weird refresh that again and there we go perfect so we have a basic modality opening up now we can actually build some functionality here that's going to invite users so let me think about how we're going to do that I guess we need to generate some sort of a unique link and connect that to the server object inside the database that probably that's probably the best approach for now for the break you know completely off topic but talking while coding is kind of hard all right let's let's build this so we need to generate invitation links to do that we want to send the event to the server which is the server invite event so let's create this inside of servers over here we'll create a server invite file here the package create a function handle server invite it will take the event that is sent by the client which is the frontend and then it will take the connection which is the a pointer to the websocket client struct and it will return nothing so we have all of this in the payload i should probably have some something like the i guess the server id yeah this is a map okay so the server id probably we need that and obviously i'm not going to like build all of the intricate details that's actually in the discord application i know this project is supposed to be a clone but obviously i'm not going to build everything stuff like uh temporary invites invites that only last for a couple of hours or a day or two or a week or a month or forever or whatever we're not gonna build all of that we're just gonna have links that I guess last permanently right so permanent links to a given server and anyone can join it's going to be the server ID and we'll use the okay idiom over here if it's not okay then we return an error with this helper method passing the type passing the message which will be invalid server ID there we go and we return because we don't want to execute any more functions if we don't even have the server ID right and then once we have this then we can actually just create the invite link so What's the best way to do this? I guess we need to store this inside of the models, I guess. So what we can do here is create another model, and we can call it serverInvite.go. And we'll just call this serverInvite. This will be a struct. It'll have the base model. Then it'll have a server. and yeah which is going to be of type server I guess and then the actual invite link so I guess this is going to be a code right which means it's just going to be a random string you call it invite code I just call it code just for gravity right and this will just be a string there we go now remind me how we actually create um foreign key relationships we need to do all of this stuff i guess so add the tag here and we'll say this is a constraint on update we want to so if a server gets updated we want to i guess cascade is fine over here on delete so the server gets deleted then we need to delete this as well because there's no need to uh have like a server invite to a server that doesn't even exist right and yeah I think that's all we need to do here and yeah perfect so we're gonna have this and then we're also gonna have invites over here invite links I guess we can call them or in what codes just to be more accurate and this will be a list of server invites and this will be a many to many and the table name can just be server invites there we go do we need to store these inside the server object I don't think we do actually yeah I don't think we actually need to store these I'm just gonna remove that I just like to have relationships between my models everywhere yes it just makes it easier to work with them but yeah i don't think we actually need that so i'm just going to remove that there we go um okay so we have the server id here now all we need to do is create a server invite which will be a random string of numbers and and letters so the thing would go is it doesn't really have like a random string generator so we need to actually build that functionality ourselves now the way to do that is to like have a like a list of alphanumeric characters that you want your invite links to like be formed out of and then you just select random indexes from that list of alphanumeric characters and then you just create a random string out of that It a lot more work and I not gonna do that myself so generating a random string in Go Because the thing is it doesn't have like its own like helper function that you can just use all at once and like get the get all the data you need right. you need to actually build all of this yourself so let's do that oh by the way we don't need to do rand.new because um this is deprecated as far as i checked so we're not going to do that but we are going to do all of this other stuff so let's see yeah okay let's do this i guess we first need to have all of this and then we just have a bunch of bytes equal to the length of the string then for every one of them we just assign the random randomly selected character from this seeded rand dot int n function and then just the car set okay got it and then we just return the the string representation of this byte slice that's all so let's actually build this now where should I put this because I already have a web utils package and I'm sure I'm going to need random stuff later as well so I guess just we'll just put it over here so let's say fun random string and it'll take a length which will be an integer I guess and we'll return a string. There we go. We'll have a character set like this. We'll create a byte slice using make and we'll give it the length over here. Then we'll have range B. We'll loop over this entire byte slice and at every index we're going to try use this or this yeah okay this and then we just need to select random stuff from the car set string so we use that over here with this index notation I guess then we need to actually get the random package mmm it doesn't have the int and function that's weird all right right never mind so we have the do we actually need this I don't think we do so why is it let me see let's just say see is ran.new yeah see it doesn't it doesn't even have the the new method anymore because it's it's just not even used anymore right oh wait I'm using crypto slash rand why am I using that I'm supposed to use mat slash rand that makes no sense yeah now it actually does have the int and function that's so weird okay so I I guess crypto has a rand package as well. The more you know, eh? And then we just pass in the car set length and this will just then select any number from zero to the length of this whole character set, I guess. And then after selecting that random character, it will assign it over here. And then we can just return the string representation of this and that should be all we need to do, right? Yeah, that's all we need to do. Perfect. Okay. Now I can just call this over here. I guess we can call it invite code webutils.randomstring. The length can be, I guess, 12 and really here, or 16, I guess, if you want to be really a bit more secure. That can be the invite code. and then we actually just need to create this uh well first of all we need to get the actual server right so let's try to do that we'll just call it s we'll do gorm.g use the generics api that gorm has say models.server passing the database which is going to come from database.connect like this and then we just select all the columns where ID equals the server ID and then select the first object passing context This will return a server or an error We handle the error over here and we can just return this I guess. And up here we can just say instead of invalid we can say missing server ID because that makes more sense. Now we have the server object. Now we we have the server and the invite code okay now we need to actually create the invitation object and store it in the database but to do that I'll just call it in or invite again use the gone dot G API the model is server invite pass in the database create and to do that first we need to actually this doesn't really like what does this return right it'll take us a context which will just be context.background I'll create this in a bit but it just returns an error okay so there's the error like so we handle the error over here again c.error AV dot a type fill to create server invite and return there we go now let's actually create this invite object which will be in models dot server invite it'll have a server which will be s it'll have a code which will be the invite code There we go. I think that's all we need to do here. This needs to be a reference, not a value. And yeah, I think that's all we need to do. Now we can actually return some sort of a success message here. I'm going to say c.reply and a reference to the reply object, which I'll create over here. This will be a webutils.wsevent object. have a type which will just be the type that we bought from the client it'll have a payload which i guess can be it'll be a map and it can have a code which will be the invite code there we go and that's all we need to do here let me just quickly make sure that everything is correct over here and i think it is yeah perfect so we have all of this now we can actually just um is the stream going fine yeah yes it is okay perfect uh by the way what is this okay never mind yeah I think it's it's fine yeah perfect I mean ultimately we won't know until we test this right so let's actually test this where do I go now I guess we we also have to actually connect this to the front end so send the actual invites send the actual event through the web socket so first of all let me also handle this because i haven't handled added the handler over here so we'll say handle server invite pass in the event pass in the client and that's all we need to do perfect so the backend is complete now we need to build all of this um and to do that that. You see, we are going to have to divide this whole component into a bunch of sub-components because look, it's called server name. It has no business handling all of these different options that we add over here. So I am going to have to divide this into a bunch of sub-components very, very soon. But for now, I guess this is fine. now we need to actually connect to the websocket so we'll do const empty object equals use websocket again our trusty little custom hook over here that can give us websocket functionality we'll grab all of these functions and then we'll call a use effect over here and the dependency array will be empty and then let's see we need to be able to subscribe to this handle invite it'll get some payload which will just be any i guess then it will um grab the what did i call it uh the code right yeah over here Grab the code which will be the invite code and I guess display it somewhere somehow For now I guess we can just console it just to make sure that we getting it and then it can return okay so subscribe to the server create um event that's where it's called right uh so okay no never mind server invite subscribe to server invite and over here just pass in the invitation there we go and then return a destructor function that's going to unsubscribe from this event using this handler there we go that's all we need to do so now I guess we can have const invite friends or actually create invite link can be a function that will send an event which will have a type which will be server invite and a payload which expects I guess the server ID as such which we do not have here do we I guess we need to pass that in as well there we go and this will be a number by the way completely off-topic but I like how all of the other languages have different like types for numbers depending on how many how much storage you want to assign to it like int 8 int 32 int 64 stuff like that float 32 float 64 meanwhile typescript is just hey it's just a number like it doesn't even try to differentiate between integers and floating point numbers let alone unsigned or signed integers let alone integers of different sizes right it just says yeah it's a number which is very simple so anyway um we need to pass the server ID here, which will be the ID. Now we need to pass it over here. Where am I using this? I'm using it in the server page over here. And we're going to pass in the ID using server.id. There we go. Now we have that. And there we go. Perfect. So now we just need to call this function, right? And we can do that over here. So we can say something like, I guess we can create another button. Just give it the same classes with a different color I guess. Create invitation link. And when you click this it should just call the create invite link function. which will send the event to the the back end using the web socket and then the back end will create the invitation link and return that in the web socket reply which will then be logged over here in the console so if I did everything correctly then this should work we'll refresh the page just to reconnect the socket there we go it's connected now we run this and we click this and yeah okay so that that broke uh there we go okay find a valid foreign key for relations or implement the value or scanner interface okay hmm so this field is broken for some reason why is it broken did i not define this correctly let me let me make sure that the table exists first of all. IT, GoCord, that's the container. Bash, that's what I want to run. There we go. Now we just open up the Postgres shell as the root user. And then we connect to the GoCord database. Then select everything from the table server invites. Okay, that's not the name. That's also not the name. does this not exist? I guess it never even got created, huh? Let me check the app. It should have been created. Like we run... Oh, never mind, never mind. So I actually do need to pass in this whole model over here. So every time you create a new model you want to make sure that you add it to this auto migrate function so that Gorm can you know run migrations for you so with that done we should be able to do this and yeah so that failed um why is it failing still let me ask GPD let me ask GPD if this is fine or not this is the error and this is the object up to you to fix this mate let's see oh I always forget this I keep forgetting this you want to actually have a server ID over here as well so let's say server ID which would be either an integer or an unsigned integer I forget okay it's supposed to be an unsigned integer got it there we go and we don't need to send this in any requests so remove it from any JSON serialization there we go yeah so you always need to create this ID field like manually so yeah there we go I'm not used to having to create this field manually you know from the languages that I come from like ORMs can just infer these things on their own so like languages like Python or raster I guess but yeah go is just like really bare-bones really simple language syntax error at or near delete okay Okay, I guess we can... I think instead of delete this is supposed to be cascade, but I'm not a database expert. I'm pretty sure it's supposed to be cascade instead of delete, I guess. Yeah, see? It's supposed to be cascade. I probably meant cascade, yeah exactly. So if you use cascade what happens is if the other, if the connected object, the related object gets deleted, then this object will get delete it as well which is obviously what we want so yeah there we go there's so much to learn for me even in just databases I want to I want to like do a deep dive into postgres and just explore it and see how that works under the hood but yeah I do that one of these days but for now this should work now so run this again I just want to make sure that the migrations are running and then I can proceed to the next task and there we go it is running you can check it over here as well I guess okay that still doesn't exist why doesn't it exist? What am I missing over here? Oh wait, wait, I'm in the wrong database. Now it should... yeah, there we go. So now it does work, thank God. So now we can run the back-end. And we can run the front-end as well. Make sure it's connected. and there we go we got it we got the link perfect I guess you can design this a bit better over here I have really kept the design of this whole application so like simple and minimal because I just want to build the functionality right now like fundamentally once you've built all of the functionality like improving the design is very very simple because like all the functionality is built you can't break anything you just have to like mess around with these tailwind classes and some html like there's no there's very little possibility of breaking something or causing some sort of an error right so i just want to get the functionality out of the way which is a lot of work already and then improving the design is easy so we don't need to worry about that but for now for now uh what can we do over here just like improve the design a little bit more uh we can do something like flex.flexcolumn I guess put this inside here and create like a field where the invite link will be we'll call this a div I guess it'll have the similar classes a border a border of grade 200 and a background of gray 100. Let's see. And the text can just be gray 600, I guess. And then inside over here, we'll have a paragraph, which will be, not even that, but the base URL of the backend slash invite slash the invite invitation code so you can have this and then you can have another state up here again we will need to reorganize all of this into a different like a different component but right now I just want to get this done so do this there we go and in here we can actually set the invite code to payload code and there we go perfect and then we just render it over here and let's see what we get refresh the page invitation and I guess what would be nice is if if I had a bit more space between all these elements like that would look a lot better probably let's do my a and space y4 let's just do that doesn't that just look a lot better so create invitation link and there we go perfect yeah I think that's all I do want to not have my buttons be so freaking big so and there we go perfect and of course you can improve this even further you can add like a clipboard or copy icon over here and then just like be able to copy this just from one click and so on and so forth but yeah I think this is the basic functionality that we that's all we need to do now all we all we need to do is just copy this paste it into your browser and whatever and it should open up like this page where you can view the server and accept the invitation right so for that we need the server join I guess event handler and that's gonna be in here close all of these now we need to handle this server join so let's see server join.go and there we go more water and I'm out of water now handle server join there we go again it's just going to take the the usual stuff web utils the event the client and now we need to actually build this how am I going to build this that's going to take the invitation link obviously which will be I guess link and be and obviously the okay keyword as well it will be in the payload that will be called link if it's not there then we need to return an error missing invite link there we go and then we need to um actually get the invitation code from this so what we can do is i think what we can do is just separate these let me see what this looks like like we can just split both of these strings on this invitation like part right uh what would that look like so what i'm thinking is something like this uh the code can be strings dot split the link and link is any so i guess we need to cast it into a string and it should separate on this invite keyword and once it does that the second part of the string should be the invitation code I think so something like this and then fmt.println code just to make sure that it is correct and yeah I think that's all we need to do I just want to make sure that I can actually grab the server invitation code from this so now we actually send this event but first make sure we handle it over here we call the server join handler over here passing the event and the client there we go and now we need to in the front end we need to build functionality to like join a different server I think we can do that over here so currently this is just like this button is just there to be able to create new servers but what we actually and why can't I open this again what we actually want to be able to do is have like a button here that says or join an existing server and if you click that then it should just ask for an invite link and we should be able to join there we go okay so we built that over here for now I'll just call this or join an existing server and this can just be an a tag or even just a button to be honest just a button and what it will do is hmm what it should do is actually what it should look like is a simple underline and i guess some better text as well there we go what does it look like yeah that looks horrible uh this probably looks a lot better yeah perfect so let's see we should probably call this create join instead of just create if we're going to have both functionalities here and also obviously change the name of the component here so there we go and and we can have another state over here I guess which will be let's call it is create and set is create this will be true if the screen is on create otherwise it will be false if the screen is on join So let see And it should be true by default Yeah. So if it's true, then we render all of this. Otherwise, we render the joining page. page so for that I guess I guess we just need to have a form again and some text input this will take a couple fields and rotation code I guess we'll just call it in white code like just keep things short it'll have a name which will be code it'll have an on change in the value okay so these will need state I'll call it server invite and set server invite. There we go. Pass that in here. And on change we have the event. We want to set the server invite to e.target.value. There we go. Yeah, I think that's all we need to do. What am I missing here now? This is what I'm missing. And then remove this. Sweet. And does it need any more fields? I guess we can give it a placeholder. This can just be... Let's see. The base URL slash invite slash code, I guess. Okay. And when you click this button, it should actually change the isCreate state to whatever it isn't, right? So if we're trying to create a server, this function, this button will take us to the joining screen. And if we're trying to join an existing server, this button will take us to the creating screen and I guess we can change the text over here as well so I can do isCreate There we go We can do something like this Or create a new server There we go and now let's see what the hell I've just built I hope this works okay there we go if I click this then we get over here okay sweet perfect yeah perfect so this has a minimum width of 2xl so I'll give the joining screen the same width 2xl there we go go refresh and there we go perfect so here we just place the actual invite code and then we just uh i guess we need a join button as well so the explorer.py2.roundedmd i'll give it the sky blue color as usual and we'll call it join and on click it should join the server so we need to build this handler now i guess and we can change this handle submit to handle create because we now have two like submittable options right now we need to create let's see join server it will take an event which will be the same as the creation which will be a button event we can say e.prevent default so it doesn't you know submit the form or try to submit the form uh we don't need this console.log anymore then we'll just try to send and it will to a server join event with some payload what am i expecting in the payload here i'm expecting an invite link which is which is called the link okay perfect so this will be link which will be link um invite link or server invite there we go sweet to her. So that's that. Now we also want to subscribe to this event I guess. Subscribe to the server join event. And... Ignore that. Subscribe to the server join event. And the handler can be handle join I guess. and obviously both of these functions are still unfinished. For now it will just do the same thing as as the create handler and it will just shut down the modale, close the modale and that's it. I'll change this to handle create. Later on we will have different functionalities here like opening the server that we just created or joined and so on and so forth but for now this is good enough and obviously we want to unsubscribe from this as well over here in the destructor function as such and there we go perfect yeah I think that's all now we should be able to just join an existence ever I completely forgot the invite link let me create a new invite link okay never mind I also want to have a close button over here because right now I can't even can't even close this model so let's create that as well down here I'll just copy this and there we go I'll copy this flex container as well and place it over here close the div format there we go perfect Okay, now let's actually like create an invitation link. And then just copy this. Close that. Join an existing server. Okay. And there we go. So I sent the event and okay, there we go. so this splitting up does work and i get the invitation code perfect uh now what i need to do is actually get the server invite and the server object which we can do by doing something like actually let get the database first from database dot connect then do invitation and we do go on dot g um passing the server invite as the model and then just say select all the columns where the code is equal to this code. Then select the first one. There we go. And handle the error as well. We can say c.error. Type invalid invite link. return there we go so now we have the invitation and we have the actual server right here now we want to add this user to that server and the way to do that is to let me see how do you actually do that uh i guess yeah uh so what you do is you add the this user to the server's members object which I'll show you over here in the models so we have a members list over here and we just add the user over here which why am I not doing that over here yeah so for some reason I'm not doing it over here I'm just I'm just adding it to the users server object over here where it's supposed to be a two-way thing so that's not good what I should be doing actually is doing both so let's say db.model s which is supposed to be the server dot association members dot append c.user which will be a pointer that's all we need to do perfect this can also be just a pointer. There we go. And if there's an error then we log that as well. Error adding member to server. Let's just say that. So now we need to test both of these now Let see What I want to do is test the creation first and then like make sure that it first test the creation and then test the joining so another group to test there we go some descriptions created I think it worked refresh the page there's the server and yeah this is the one perfect so creation works now I want to join an existing server here's the invite link press join and no error so far so I guess this just didn't get saved yet okay so and actually instead of duplicating all of this I want to be able to just add the member directly right so what I want to be able to do is have like a server pointer receiver over here with the name of add member and then just what it should do is just take all of this and like handle it all for me right so do all of this don't need to print this the database will just be database.connect and declare this c.user so we need to pass the actual user object which will be a pointer to user as such we can replace c.user with just u and what we can do over here is say s.add member u c.user there we go now i want to make sure that this works one more time uh undefined error let me save this okay everything seems to be fine over here okay perfect uh now let me just test this one more time just to make sure that it works and we'll create another server i'm sure you're bored of seeing the same image again and again uh test 31 or whatever test we're on right now and okay refresh the page it did work i know okay never mind it didn work okay seriously didn work okay why did it not work let see test 31 again create nothing happened it should have worked there's no errors in the logs I guess it's just not being added then right yeah I think it's just not being added hmm I wonder why it's like I'm not doing anything like like I'm using pointers everywhere so it should work perfectly right Do we need this actually anymore? Because this is already like a pointer. I guess we probably don't need a pointer to a pointer, right? Maybe that's the error. Refresh again. Let's say test 31 again. This is like test 34 at this point, but... Okay, create. No errors. And I think that's the server. and yeah there we go perfect okay so that works next we just need to handle the creation which not not not the creation but the joining which should be very similar all we need to do is get the server and say add member and the member will just be the client user and once we do that and there's no errors or anything then we can just do a reply which will be a webutils.wsevent it'll have a type which will be ev.type so basically the same type that the client sends us it'll have some payload which will be as such and I guess we don't really need a payload over here because all we really need is like a success message and then the client can just refresh the page and open up that server's page or whatever right so um yeah we don't really need to do anything special over here i guess i guess i'll just return like a that's true for now and if we need something else we can obviously add that as well but for now i think this is good enough uh there we go then just do c dot reply reply there we go what is this error over here that i'm getting uh okay never mind okay Alright. And this is a bit weird to test because I already am a part of these servers. But what we can do is... Nevermind, I need to refresh the page. Actually what we should do is be able to leave servers and then we can actually be able to join them back and see if that works. uh Refresh it again. I don't know why it doesn't open up the second time. Okay Paste paste paste paste. Where's my invite link? There it is. Join. Sweet. That works. And No, it does not work Oh, oh, wait, wait, never mind. It failed because I'm already a part of this server, right? Because, yeah, because I already joined this server, I'm already a part of this server, so it can't, like, re-add me, which is why we get this error. Insert or update on table servers violates point key constraint. Servers owner. Insert or update on servers owner violates key constraint. Let me see. Am I supposed to get this over Adding server to user okay Let see let see why is it giving me an error for owner when when all i actually doing is trying to add it to the many to many fields over here like the owner is completely untouched right i'm not even doing anything with the owner over here so why is it like this right let's say paste in all of my code and see what it says but I'm not doing anything with the owners right like the server has already been created I'm not doing anything with the owners at all so this is weird hmm do I actually need a pointer over here? I really don't think I do. I really don't think so. Because, like, creation works, right? When I create a new server, it does work perfectly. So why doesn't it work over here? That's the conundrum. Let me log it. Let me log the actual server's owner. the username I guess. Let me actually log this and see what we get. And there we go. Let try refreshing and then joining again Oh my gosh Okay, same error. And no owner. That is, that is weird. Oh, oh, never mind. Okay, it's because I'm not preloading the associations. So to do that, I guess what we need to do is over here, say preload. Let me see. There we go. This is going to be called the, let me see, the server, right? Yeah, there we go. So because I'm not preloading this related object, it's just creating an empty object in its place, which is obviously not going to work. But yeah. so now we need to just return nil i guess over here because we don't need to like have any custom queries or whatever uh this is getting a bit long so what i'm gonna do is do this just to like format it a bit better there we go so now it should work perfectly and there we go it's running refresh the page paste in the invite link again sweet okay but still didn't print the server owner but there's no error so I guess it does work now okay I guess to to print the server owner I probably need to like preload the owners preload the owner object as well that just way too much work what we can do to make sure that this is working is to just print the server I guess name that fine and you can also probably print these owner ID because that just an integer so it should be able to load that and there we go if these things if these values exist then the server is being loaded properly and everything is working properly so let's make sure of that and need to refresh the page again this is so much work paste in the invite link right here and join there we go let's see okay yeah so we get the name of the server we get the ID of the owner of the user and yeah perfect and this isn't this is an error this is not an error this is just a warning that this is slow it's slow because I'm running all of this on my local machine and my local machine sucks obviously if you run this on an actual server built to withstand these things and this will not be slow it's just slow because I have a slow computer anyway all this works I think I'm gonna end the stream at this point we've been going for like more than an hour already we built the invitation functionality we built the joining functionality obviously a lot of this stuff is still very like early stage and just not finished completely there's so much more stuff to do to just make this whole system much more resilient much more like um to handle failure states more gracefully and so on and so forth to improve the ui there's so much to do on the ui as well on the front end side there's a lot of work to do so yeah we're just gonna keep going at it one step at a time and let's see where we get i'm gonna end the stream at that point there we go so uh yeah lots of coding done today and uh we'll see what we do next time

Share this article

All great things started with a conversation

If you've got a cool project or opportunity and you want me to be a part of it, set up a free meeting with me here, and let's talk. 😊