Hogwarts On Rails - Part 3

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
so where we left off is we had two models already created they were associated with each other we had our house model where a house just had a name and a certain number of points a student model exists where the student has a name and the student also has a reference to a house which ends up being a house ID foreign key and then we had created a House's controller which had two actions in it one action to retrieve all the houses and an Associated view to display them and then one action to retrieve a house by ID an Associated view to retrieve it and we had some routes that would lead to those actions so we had the route route going to the houses index we had slash houses / a ID placeholder going to the show and that's how this ID is present in the show so that we could look up a house by ID and so we're gonna continue by creating a new controller which will be very similar in style to the houses one again it's using only two of the seven possible restful routes it's using the index and the show and it's going to do almost the same thing and the idea with rails is that you can get pretty far with your controllers just cherry-picking which of the seven restful routes you want to include and then you can build like a crud out based off of that right because if you have the full seven routes you will have one that is for showing all of the collection one that's showing one of the collection one for creating I'll actually a pair of routes for creating a pair of routes for updating and then one for deleting those all your different crud actions so we're gonna add the students controller it's also going to add two new routes to our system so the collection route for the index is gonna be at slash students for showing an individual student that's going to be at slash student slash ID there will be one view associated with each of those action and we will proceed from there so that's where we'll begin I have three different terminals running one running my server one running the rails console and one where I can just type in commands and it's at this one where I can type in commands where I'm going to begin by creating the new controller so I'll say rails G for generate what I want to generate which is the controller the name of this controller is the students controller again conventions here just dictate that we typically map controllers for models and then the controllers are the pluralized versions of the model names so it's the students controller that map's to the student model and then I know up front that I need two actions so I can ask for them index and show and if you ever typo anything in this sort of command and get to a point where like you misspelled into action you misspelt show where you misspelled the controller and after it runs you can you could run a rails D controller name and it just removes all of the files and folders and everything that it created associated with what you asked for and then you could run the generator again so I'll run the generator like this rails G controller students with two different actions and that creates for me a few things I can go into my source control and I can say added a student's controller your source control is some maybe not gonna work I'm not too sure you've cloned a repository that you don't have ownership over so you may be able to do adds and commits but you definitely won't be able to push those back up to my repository because you won't have you won't have write access to the repo up on github so I'm gonna open up what was generated there in the app controllers folder I have my students controller gonna double click on that in the app views folder there is now a student subfolder and I can open up both of the views inside of there I'll probably need access to the layout so I'll go in the layouts folder and open up the application dot HTML GRB that's inside of there and in the config folder I want access to the routing so there's the router RB that is in there the generator put two routes into my system I don't want those generated routes I'm gonna create my own so I will delete those so based on this planning document I now already have my students controller and when we look into it we'll see that there is a index and a show action there empty right now and I know the plan for my routes is that a get request to slash students and they get request to slash student / ID well themselves route to those two actions I have to create those routes now and I can create them manually or using the resources command manually it would look something like a get request to students would go to the students controllers index action so it's always like the HTTP verb the path and then where it's going and I could even associate like a route name with that and as command I don't want to do that when rails will generate those for me so you just know that you can always generate routes manually if you especially if you want to sort of step outside of the seven provided restful routes you can treat them on your own any route you want by verb by path and where you want to point it to but because we're staying within conventions I can just go to the resources command and say I'm working with the students controller so make me some resource based routes for the students controller and again like the house controller I only want access to the index and the show and when I save this robocop will rewrite that to some a it looks like this a percent I which is just a shortcut for an array full of symbols so here I'm sort of explicitly making an array of symbols it'll just be shortened down to this when I hit save and so that in comments here will give me something that looks like this hey students I get slash students that's gonna go to the students controllers index and they get request to slash student slash some ID which is going to go to these students controllers show like that so I hit save Robocop will read that rate that for me the index and the show already have some HTML on them just some placeholder HTML there's gonna be an h1 inside of both of them that will specify which controller in action is sort of being accessed and if I look at my controller itself the enix in the show are empty right now but I can at least test my routes out so if I go to slash students I should see the index view this one right here and if I go to slash student slash any number I should see the show so if I go over to my browser and I go to slash students there's what I was expecting if I go to slash students slash any numeric ID regardless of it exists in my database or not because it's we're not doing any database access at this point it'll tell me that it's properly gone to the show view so that just at least gives me the confidence that my routes are set up correctly and then note that that hTML is being brought to us inside of a much larger full HTML page by way of the application layout so this message up at the top here and this link to home that's coming from the layout so if we look in the application layout we can see inside of there there's that h1 there's the link to home there's the footer and the individual views are being injected into the layout where it says yield and so now I can go and actually implement these two actions here I like to put just in a comment above them the actual sort of HTTP requests that will trigger those actions it's not a requirement I just like to document them in this way so I'd say here this is a get request to slash students and this is gonna be triggered by a get request to slash students slash some ID and just like we did with the houses controller here I can load up all students I make it an instance variable with the @ sign in front of it and that way it is available automatically to my views and that's just a quirk of how rails operates it takes the private instance variables and makes them accessible inside of the views and so I can go to the student model and say like all or if I wanted to like for example order all of the students by name I could say like give me all the students ordered by name and then I could go over to the Associated view because unless we circumvent the default action by say doing something like a redirect what's gonna happen is that at the end of running this index action it's automatically gonna try to load up the Associated view so auto magically loads the associated view in this case is in the app views students folder and it's got the same name as the action so the action is index the view is index and then all of our views are HTML dot RB and then this add students variable will be accessible within there so I can go into that view I can delete what's in there right now I'll add an h2 and I'll say all students I can put in a little if statement to say like if the students collection is empty do one thing otherwise do something else so it's empty we could just say there are no students in the school so just like a helpful little message here we're gonna make an unordered list of students by using a loop so if we didn't have this little message in there all that would happen is like an empty ul would end up inside of our document and that wouldn't be overly helpful for anyone visiting the page and so inside of there I can go to my students collection and loop over each student like that and in this case I'm just gonna drop down an Li for each one of them where I echo out the student dot name property of each student object in my student collection and most rails views look like this sort of some mixture of decision statements and looping statements you really don't want any computation to be happening inside of the views you definitely don't want to be ever directly accessing the model well from within the view it's the controller so if you have like extra logic around processing the request the controller should be handling that if you have special extra logic around the sort of the domain knowledge of the system that needs to go into your appropriate models and the controller ends up being like the traffic cop that sits in between the views in the models you never want to directly access the models within the view because that would be overly coupling the view and the models together so if I go to this running version of the site and I just go to slash students that should trigger this controller action it should load up all my students and it should display them down below that I not save it I've noticed a few times what has happened with my application I don't know if it'll happen for yours in the same way but it's the rails server incorrectly sometimes caches things and so I think I'm gonna have to for mine control C on the server start it back up and see if that flushes the cache yeah that's frustrating that should never happen in development mode rails is not actually supposed to be aggressively caching anything and nor is the browser you're supposed to anytime you make a change to a view that should be immediately reflected in your development server however if you're ever in a position where you know you've made a change to your view and you're just not seeing that change happen when you reload the browser that is the sign that that server has glitched a little bit and you have to go to your server control see it to stop it and then restart it yeah yes so the controller looks like this is the only one we're working with right now we're assigning the return value of all the students ordered by name to an app students variable which we then use the side of our view and I can now go to my gift and I can say implemented the student index action view and if I wanted to test my logic out the logic that had to do with like whether there was students present or not I could go to my console my rails console and I could just delete all the students I would also have to delete the associated houses because there's a foreign key reference there so I could go to house dot destroy all you don't necessarily have to do this I'm gonna repopulate my database immediately afterwards but house dot destroy all would destroy all the houses you know like that for industry straight old I do I have to hide delete the students first I don't think so how many houses do I have why don't you like them oh it is the other one her student Don destroy all all so I've now deleted all the students just so that I could test that little path and again anytime I put something like that in my code if I was developing this not in front of the classroom I'd be doing so in like a test-driven way and so I'd have a test that would test that logic out for me but because I'm not doing this in a test-driven way I want to assure myself that the decision that I put into my code actually works as expected right I don't want to be surprised you know two days down the road or you know 20 days down the road that some part of my application doesn't work as I intended so if I put an if statement into my code where there's two possible paths I want to check out those possible paths or have a test that that's those two possible paths to know that they're actually properly working and so now I'll go back to my command line and just run my rails GBC it again to get that data back in place make sure that runs properly there you go and the reason why I wasn't letting me destroy my houses is that each student has a foreign key to the house and so there would be a bunch of orphan students if I tried to delete the houses first and now we can do a similar path but for the show so we have a get request to slash student slap some ID that ID is going to end up in the params hash at position ID and so if we had called it something else it would be at a different place holder inside of the params hash params hash is where our parameters end up and so inside of here I can create a student variable because it's just a single student that I'm loading up and I can go on I can find that student using the ID that is coming to me from the URL and just like above here the associated view is automatically gonna be loaded up and so that is gonna do this and that view will have access to this act so you can object which is going to be an object of type capital S student so now it'll be up for me to go into the Associated view and display that data so right here I can make like an h2 I can echo out the student name and then I might say something like this student belongs to house then I can go to the students house so I could say house I would just go quickly over to the browser and I'm gonna check that if I I need to know a particular primary key of a student and so from my console I would just say what the last student is that will let me know that I have a student with a primary key of 124 in it and so I should be able to go to slash students / 124 to see this particular student right here and so I should see Garrick as the student and if I want to know this student's house name its Hufflepuff so in my data again I want to validate that the code is working as I expect it to and so I'm expecting when I ask for student 124 but I see Garrick Oh levander and I see that Garrick is part of house Hufflepuff so if I go over here I put in 124 and I see that my expectations are correct it's done what I wanted to so I like to see like programming and debugging sort of like the scientific method right you're making Lille hypotheses about how you think your code works and then you're testing to see if that hypothesis is correct and if it isn't you're fixing your code because there's a bug in it and yours might not be 124 right you may not have run your seed script the same number of times as me so you might have to go and find a different ID and so that's good this is showing me all of my students it would be nice if I could link to those students it would be nice if I could link to those students here as well right so we have a page for each one of those students let's link to them and we could do that in two places so the two places where the students are being shown is at flash students here and on the individual house page so that's the house show page so I'll open up that house show page as well so that's in my half views houses folder and it would also be handy for me to be able to navigate maybe by way of this little menu up at the top here to that slash students page I don't want to have to have the user type in slash students up here to get to that page they should be able to navigate by way of a link so we can do that I want to see the routes that exist on my system and the easiest way to do that is just to put in a non-existent route that brings up at least in development mode this routing error which then shows the routes that exist and it also shows the route helpers that exist so I can see if I want to get a link to the students index action which is this one here I can use the students paths the students path helper so I will go to my layout file that I opened earlier and up here in the header I will just add in like a pipe character and then I will make another link to I will say link to in the link texted students and to help her I said was these students hath helper and in this case the students path helper doesn't need any extra information to know how to forge that link because the the link itself is just slash students it doesn't have for example an ID placeholder in it so the students path has all the information it needs to generate the correct link so we use link to to generate that a href for us and so if i go back to my browser and i go back to say the home page there are now two links up there one to home and one to students i can navigate back and forth between and then as i said it would be nice to be able to have these be links to the individual student pages for that the routing system needs a little bit more information so if i go into the app students here sorry the app it'll be the index that I want the a few students index I want to make this a link to each student's page if I go over here and again bring up that routing error we'll see that each student's page the student show action which is that individual member page for the student includes an ID and the helper named is student path singular i can't simply do this though i cannot just do well i want to link to where the link text is the student name and they helper is student path because that doesn't give student path enough information to make the link because the student path includes a placeholder right it needs to know which student I'm linking to by ID and so if I try to do this I'm gonna get an error so I go back to my students page we can see that error which it says no route matches action show student missing required keys ID so it gives you a pretty direct idea as to what's wrong here you've tried to forge a link using the routing system but you were missing some required information you're missing an ID so all we need to do is pass to the student path an object that has the ID that we need which is the individual student object that we're working with right now so I'm going to say student I go back over here and I reload this page lo and behold I've got all these links if I click on one of them I get to that student's page and it properly puts their ID into the URL for me by passing the student into the student path the nice thing about rails is when you really work with its conventions and you don't stray outside of those then you can even do things in sort of a simpler way and it's so common to have this pattern where you have an object of a particular type and then you have a path with the same name as the type so you can actually just get away with just passing student object itself saying link to the student and rails will just infer to itself it's like oh you've given me a student object I'll check to see if there's a student path in the routing system there is it'll use it so that if I reload this page it does the same thing and I can now that do the same thing inside of the house show pages if I go to any given house I can make all of these links to the appropriate students as well so if I go to that which is my app views houses show I can make it so that the student name is a link to the student name type LS and where am I linking to I'm linking to the student so this is in my houses show view changing the text to be a link to the student so if I go back over here those are all links now and they work as expected there's Hufflepuff there's a student in Hufflepuff they are in Hufflepuff everything seems to be working correctly just gonna take a quick peek here yeah that makes sense it might also be nice in this students index action to specify the house of each one of these students and also linked to the house of each student we already have a way of linking to the houses we built that before here it is if we looked at that view that's the house index view we can see that we are linking to those houses in the same way a link to with some link text passing in the house object and that properly links to the individual houses so we should be able to do that inside of the students index so one in the student index when I'm looping through my collection of all students I could say something like student name and then I could say of house and then I could link to the student house name that's gonna be the text so I'm using my Association I in my model we have a belongs to and has many Association active record association set up between a student and a house making use of that foreign key the house ID foreign key so I can just chain from the student to its house object and then on the house object access to the house objects name property and then I can for the second argument here just link to the student house if you put a period at the end of it I put this link on a different line it won't actually be on a different line in the rendered HTML because HTML ignores extra whitespace and extra new lines is just there for for readability in my view so that'll be just one long uninterrupted sentence in rendered output and so if I go back to my browser and I go to the students page we now see the student names and their houses there is a problem though did I talk about in this section and +1 issues yeah the idea of like an M plus 1 has anyone heard of the sort of the classic problem in applications that typically deal with the database and often involve an object relational mapper like Active Reppert called the n plus 1 problem have you heard anyone refer to that before o our application suffers from an N plus 1 or the performance here is degraded by an N plus 1 you'll hear that and I'll show you exactly what it means if we look at the server that is running when first we'll show you what things look like when I will temporarily get rid of the call to this house so in the view I'll remove that just temporarily I'll save my view and I'll reload this page in the server there was to get all of those students just a single HTML that was triggered or sorry a single sequel statement that was triggered select student star from students ordered by student that's coming from the associated controller that's this right here one sequel statement generated by that one call if I go back to the view though and I put the house in there how many sequel statements should there be in my output to retrieve the students and all of their houses if you were writing Ross sequel yourself you should be able to do it in one sequel statement at most - right because you could do like a join or you could get all of the students and then because you know all their IDs you could find the houses that are associated to those students in a single sequel statement but watch what happens when there's an ORM in place when I add the houses in what happened was I went and I got the students and then for every individual student we query for their house one by one by one by one by one that's the n plus one problem because instead of one query or at most two queries we have one query to get all the students and then depending on how many students there are there will be n subsequent sequel statements generated where n is the number of students to fetch each of their houses that's incredibly inefficient right especially if you had thousands of students you could end up firing off thousands of sequel statements there is a very quick fix around this but it's sort of on the programmer to make that fix active record we'll try to delay its generation of sequel to the last possible moment to be efficient so it doesn't fire off the sequel here but the minute we start looping through the students it does fire it off and then all of a sudden you're asking for each student's house and active record doesn't have that information so for each pass of the loop here it's having to fire off another sequel statement so we can just hint to active record up front our intention which is that yes in the view we are gonna need not only the student but we need to include the information about the house so I can just put in here includes house and by hinting to active record that I will eventually be using house information associated with these students we have rid ourselves of that endless one problem and so n plus one problems are one of the largest sources of slowdowns in web applications there are gems that you can actually plug in to Rails applications and their sole purpose is that in development mode they just look for and plus ones and tell you about them and so the dot includes moves our n plus one issue accessing the student how is this J so with that in place I can go back to my server quickly I'll hit enter a few times just so that we see a little break in the text I will reload this and you can see now we have simply done two queries one to get all the students and then one to get all of the students associated houses and there they are and the way it did it was it looked at the collection of students that was present it saw that out of this collection of students there were only a certain number of houses that need to be retrieved and it found those houses by ID and so the sequel statement was a select star from houses where the house IDs were and then there's like the five different IDs that are associated with the variety of students and so it just needed to fetch the five houses rather than needing to fetch the house over and over and over one per student so that's a nice little hint we could also put that over here but we're not really suffering from an M plus one here in the show because we're just getting the student and then showing the house at most there's gonna be two requests already it might be handy just to hint to other programmers our intent here so it won't save us anything but we could mark this as being like somewhere in the view we are gonna make use of the house but we're not gonna get any performance boost by that because there's no n plus one problem in the show we only have a single student fetching their house is a single other request so it doesn't doesn't help us performance wise but it might make our intent more clear to other programmers they know up front here Oh Kyle's probably making use of the students house because he's marked it as it includes here so that solves that little problem no more n plus one in this page any questions on your behalf about anything that we've done up to this point in terms of our creating our application which now has two models and two separate controllers and a total of four routes so it's it's often quite especially with a complicated system like rails it's often easy to watch and say yeah that makes lots of sense and so what I'm gonna do now is I'm gonna ask you to do some coding yourself just to make sure that when you actually put it into action things make sense and so what I'm gonna get you to do is to create a new model which is going to be a teacher model a new controller which is going to be a teachers controller and this is gonna mirror very very similarly what we did with students so it's not like you have to do anything too new here and one would argue that if I was making a real application here the teacher model and the student model could actually be integrated into one like person model where that person had a different role like is this person a student is this person to teach her but just for the sake of having a new model for you to create that's already been sort of visited in a way by way of the students I'm gonna sort of break it out into two separate models so a teacher just like a student is going to have a name which is a string the teacher is going to have a foreign key that references a house and you're going to need to make sure you go to the two models and forge the association with the Hasmonean belongs to once you create your new teacher model you're gonna want to update the seed script to make sure you're generating fake teachers and then you're gonna want to rerun that seed scripts so that you have a bunch of houses that each have students associated with them and maybe like one or two teachers per house you're then going to generate a teachers controller which just like student is going to have to read actions a collection action for finding and then displaying all teachers and a member action for finding and displaying one teacher by ID you're going to in the routing file create the two associated routes with the resources command you're going to create the Associated views the index in the show one you're gonna implement the content inside of them and if you get stuck anywhere along the way just let me know and I can help you work through any problems that crop up and so I'm gonna pause the video now for you to work on that so we're now returning to the point where I've got the teachers model is now implemented and the teachers controller is implemented so on my home page I now have three different links up at the top home student teachers they just put that one in so I have some way of navigating to that teachers controller I click through there we have a list of all the teachers and a list of their houses if we look at this controller it would have suffered the same end plus one problem as the students because in the view we're looping over the teachers and then requesting each house in turn so we need to have that includes statement in there which I'll see in a moment we can now navigate to the teacher's houses but we can also for any given teacher navigate the teachers page and so how that was implemented well if I head over close a bunch of my existing tabs here in my model I now have a teacher model not much in there I could probably add some validations just like I did for the student I thought just I'll just copy the validation that I have that's something I didn't mention but I might as well put that in here teacher is required to have a name in order for the object to be valid a teacher belongs to a house if we go to the other side of the Association the house has to has many's this is one of those instances where you can't just stack them side-by-side so you can't say has many students comma teachers that has many command just doesn't work in that manner so you have to have to has many statements one for students one for teachers so that way a house object you can now go to dot students or dot teachers to see the associated collection and for a teacher you can now go to God house on a teacher object to see the associated house by way of the foreign key so that was the the model that I created at any time if you want to see what your database looks like you can always go into the DB folder and look at the schema RB file and it's basically it's almost like all of your migrations sort of in one showing sort of the fact that okay we have a houses table and these are the columns we have a student's table and these are the columns you can see the foreign key on there same thing goes for teachers you can see the foreign key on there one of the things that I've noticed when adding foreign keys to tables after the fact so in this case we created the teachers database we did so with this migration and when we created teachers is when we added the foreign team sometimes things are not that clean you might have created the teachers table all in its own just with the name and then realize you know some days or weeks later okay I need a foreign key on this and then there's a way of creating rails migrations that are almost like alteration migrations so it would be a migration simply to add that foreign key and one of the things I noticed that just a bit of a gotcha is that with sequel Lite sequel Lite gets upset about adding a null false foreign key once the table is already created and the only way to get the migration to run is to allow nulls on that column that's not a problem when you move to Postgres but just know that if you ever get into that situation in this course where you're adding a reference after the fact of the table sequel Lite will complain until you change that null falls to null true so that is the model there is a controller that I generated with a rails key command and it is the teachers controller and it looks very much like our student controller and that I'm loading up a collection of teachers including the houses and a single teacher including the house ordering them by name or finding by the ID from the URL so very little is different from what we did with our students here and then in the Associated views again not that different from the index and the show view for these students by going to my teachers subfolder I can see those the show just shows that individual teacher it links to the teacher's house by name in the index I test to see if there are no teachers but if there are I loop through them linking to both the teachers show page and the house show page and the only thing left is the routing system if I head over to the routes here there is the teachers route and I can comet them in the same way teachers it's going to teachers index and I get requests to teachers / some ID is going to the teachers show the only other thing that I will show briefly is if I remove the only here and I ask for all of the resources associated with teachers I can go to my web app I can put in a route that doesn't exist and I can see all the seven restful routes that are being generated for me so when I ask for everything I get all of these routes right here the one that we have been using or the two that we've been using our the index one and the show but it's worth noting that if you need to create new teachers by way of your website you're gonna want these pair of routes which are they create and the new routes just having the routes doesn't implement any of the functionality but it puts the the routes in place and sort of the standardized way with the standardized paths and the standardized HTTP verbs and so the new the idea behind the new so going to a get request to slash teacher slash new that's going to be up to you when you generate that view to make a form for filling out details about a new teacher and when that form is submitted where it gets submitted to is this teachers create action and it's the create action that actually does the active record creation same thing goes for editing there's a pair of routes there slash teachers slash some placeholder ID / edit that also it's gonna be up to you to implement a form that loads up all of the teacher data and displays it for editing and when that form gets submitted it's going to be sent over to the update action and for historical reasons the update action triggers both with a patch and an HTTP put request and then there's also a delete that responds to a delete request to slash teacher slash ID so there are a number of these routes that are member routes that have an ID in them that are for directly viewing or manipulating an existing object and then there's a number of them that are more collection routes that have nothing to do with a particular member and if you ever want even though just using the resource doesn't sort of build up any of those actual actions and views for you anytime you run the scaffolding man so rails G scaffold it will create all that for you so sometimes I just do that so I can reference like what is the standard way of building the create action of view or the new action of view sometimes I just have like a rails project off to the side and all it contains is a single scaffold if resource so that I can reference how those things were done if I need that kind of functionality in my own application so those are the seven restful routes I will go back to only requesting two of them here just by saying and that's all I got for you for today and so tomorrow we don't have any class because I will be at the directions conference so yeah no classes tomorrow we will have a class on Friday though where we continue this application so that's sort of the flow of this courses is that initially in the course there's a lot more lectures than there are labs and then when it comes time to actually work on the two individual projects we sort of switch over to there's more lab time versus lecturing time we're still in sort of the lecture heavy portion of the course where I'm trying to get through as much rails material as possible to get you to the point where you can implement your individual projects starting with that first project any outstanding questions about this application or even the project that's upcoming all right thank you very much for coming to class today and working on our Hogwarts app
Info
Channel: Kyle Geske
Views: 239
Rating: undefined out of 5
Keywords: Ruby, Rails, Ruby on Rails, Rails 6
Id: IXb7y6JNa7o
Channel Id: undefined
Length: 53min 50sec (3230 seconds)
Published: Fri Feb 07 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.