Nesting Ruby on Rails pages creates a smoother, more satisfying user experience. In addition, it's a good idea to understand how to pass parameters in URLs. Learn how to build a relationship between controllers for subjects, pages and sections by nesting. This essential training video will help you understand how nesting creates a more complete user interface when you nest pages in subjects.
In our simple CMS, we have one controller for editing subjects, one for pages, and one for sections, and that's how it should be, each area should have it's own controller for it's own cred. The problem is, that right now they're completely separate, and I think our application will be more usable, if we had a relationship between them. Specifically, if we nested each one inside of it's parent. What I mean by Nesting, is that instead of going directly to a list of all pages, you would first select a subject from the subject list, and ask to see just that subject's pages.
Then the page list would be only pages for that subject. You would then pick a page from that list to see a list of the sections for that page only. It would be more of a tree structure that we would be navigating. Let's walk through the process of nesting pages inside subjects together. And then you can try to do the same with nesting sections inside pages on your own. First, let's start by getting an overview of how it works. The first thing we're going to do is, we're going to go to our subjects index page, and we're going to add a link to the pages index page. That'll allow us to go from the subjects to the list of pages for that subject.
The most important thing though, the key to making this work is that we're going to send the subject id in our link parameters. Then that pages index action will be able to have access to that subject id and know what subject id called it. Then in the pages controller, we can find the subject using that ID and we'll do it using a before action. We used before actions before when we were restricting access. Here we're going to use it so that we always find the subject before each and everyone of the actions in the pages controller. Then our actions can start to take advantage of knowing what subject called them.
For example, our index action can scope the list of pages by the subject. And our new action can use the subject to preselect the page's subject. Most importantly, though, all redirects inside the controller need to preserve that params subject ID. It needs to be send with each and every redirect. Once we're inside this nested structure. We have to maintain it and stay inside it and always know what subject ID we're working with. To that point, the next thing we'll need to do, is go to the views and to our templates for pages and make sure that all links and form actions also preserve the subject ID.
Let's try it now, so you can get a feel for how it works. Before we do anything else, let's launch our web server. So from, from the root of our application. We're going to type Rails Server, we go to Firefox. I'm already on the Admin page, I'm going to click on Manage Subjects. And what I want to do is for each one of these subjects, I want to add a new action here called View Pages. And when I click that link, it'll take me to The pages would show me a list of pages for that subject only. Let's add that link now. So, in our app, inside views, inside subjects, you'll find Index, and let's scroll down.
I'm first going to get rid of these straight straight erb tags I have here at the top. Let's scroll down right here, and I'm going to copy the show link and just duplicate it and change the name of it to view pages, and then let's also take the action out of it and we'll write a new action. When we click View Pages, it ought to go to the controller, for pages. And we could say that the action is going to be index, but that's the default so we don't actually have to specify it. But we do want to provide the subject ID. We want to make sure that the subject ID is sent, and that is just subject.id, just like we have here for show, edit and delete.
So lets try that out. Let's save it, switch back over to Firefox, reload the page. There it is, it broke my layout a little bit. Let's just tweak that. Let's go into app assets> style sheets and then admin.css. If we scroll down, here's actions. That's the, the actions area. And I've got it with 200, let's make it with 230. Let's see if that works. Let's reload it. That gives it a little more space here so they are all in one line. So now, when I click on my view pages actions for revised subject.
You'll see that I'm seeing the pages. Right? And it is passing in subject id right here but I'm not seeing a list of just the pages that belong to revised subject. I'm seeing all of them including the one here that belongs to initial subject. I now need to switch over and I need to go to my controller. And we need to write our controller code. So inside pages controller, the first thing I want to do, is I want to find the subject, that belongs with this action. Now, I could do it just here in the index action, but I want to do it, in all of them, I want to make sure that every single thing inside the pages controller.
Has access to that subject. So I'm into with the before action. So with before action, I'm going to call it just find subject. Before action find subject then I'm just going to skip down to the very bottom of the page. And make a new method here it's called find subject. And lets say, if params subject. ID, if that's sent, then let's set subject equal to subject, find, params, subject, ID.
See how that works? So every single one of the actions in this controller is going to call this method, first thing, and if it has subject ID sent, then it's going to find that subject ID in the database, and set the subject equal to it. Lets save it. I'll jump back up to the top. The index action then needs to take advantage of that. So we want to scope the pages so that we are not just getting all of the pages sorted but we want to find the pages where the subject id is equal to at subject.id.
See how that works? Now, this kind of scoping is perfectly fine, but I do want to show you a slightly better way to do it. Just put a comment there. We can have pages equal to @subject.pages.sorted. Here I'm doing the same thing but I'm using the relationship from subject to pages. Right? This are the pages that belong to the subject. It's the same thing. This is saying find the pages where the subject id is subject id. Well, when Rails goes to find these pages, it asks for the pages where the subject id is equal to subject id.
I think this syntax is a little cleaner, showing that we're going from the subject to the pages. Let's try it out. Let's save it. Let's switch back over to firefox and just reload. And there we are. Now we're seeing only the pages that belong to the robot subject. Now there were a couple more things that I said we needed to do on our pages controller. One was we were going to skip down to the new action. And we're going to make sure that in addition to having a default name, we're also going to have a default subject. So the default subject here, ought to be. Subject id. It's going to be equal to, and it's going to be at subject.id.
That's it. We'll set the subject id when we initialize the object and so by default that's the subject that'll pop up. The next thing I said we need to do is we need to make sure that all of our redirects maintain the subject id. So here where we have our first redirecting create, after we create redirect it action index, well we don't want to suddenly un-scope that list and see all the pages, we want to make sure that we are still seeing only. The ones that belong to this subject id at subject.id. Just going to copy that, and we'll just jump down here to update where we have another redirect.
We're going to make sure that we add it there, so that it's in that one as well, and then let's skip down here to destroy, and we'll do the same thing here in destroy. Okay, so now that that's sorted out, the next task is that we need to switch over, to our pages templates. And we need to go through all our templates, and review them, for places where we also need to maintain, this parameter. So let's copy that because we're going to do a lot of pasting of it, so let's go to the index. Let's go to here we have add new page. We add a new page. It's going to be a new page for that subject, so we have to pass the subject id that we found.
At subject is available to me as an instance variable, so I can pass that in, and then down here when we show a page, we want to pass that in as well. When we edit a page, and when we. Delete a page, so make sure you paste it in the right place each and every time. Oops, let me just put this for the parallel structure. I'll put it right after the ID, so all of those links maintain it now. So let's save that, let's now goto our different forms. Let's go to Show page, I don't think we have anything on there first. Back to list, does go back to the Index page, so we do need to put it there.
And, lets go to new. That has a back to list at the top so we need to put it there as well. And after create. When we create it we are going to want to make sure we pass on the subject id. Lets go to edit. Same thing on the back link. And here right after the id. And lets go to delete. And lets do the same thing there as well. Okay. Okay, that should take care of all of the links making sure that they all maintain that subject id parameter that we need for this nesting to work.
And sure enough, if we go back to Firefox, and we reload the page, let's click add new page. You can see that our subject is selected here, right? This is the current subject that we're on. If I click the back to list button, we go back to the pages and we've still maintained that scoping. We're still nested. We're seeing only the ones for revised subject. Now, notice here that there's no way for me to go from pages back to the subject, right? There's no way for us to go back to this revised subject. One way to do that is just to take another back link here, take this back link that we had, we'll put it at the top of our index page.
Let's start right here above pages index. We'll do back to subject. And that's going to then, of course, go to a different controller. The controller's going to be the subjects controller [SOUND] And the action is going to be index, and we don't need to pass the subject ID along to it. So let's call it back to subjects just to make it plural, there we are, reload the page back to subjects. It'll take me back to this subject list. Now, one last detail, let's add a link from Subjects back to the main menu, let's see, I think have exactly the link that I want, in my Admin Area, on its index page, the Back to Menu link, just going to copy that, we'll go to subjects index.
Put it up here at the top, that will take me back to the menu. And then, when we go to our menu page, which is access index. Let's, load that up so we can see it, and click Back to menu. We still have manage subjects, manage pages, and manage sections. The idea is now that we would get rid of these two. So you wouldn't be able to go to pages and sections directly. You would just go through manage subjects. And let's change that to manage content to better describe what it does. So now in our admin area, we just have a link for manage content. We go there, we see a list of our subjects, and we can view the pages for each one of those.
Then we want to make a new page we can click a new page make a new page we can edit pages and every time we're still going to have this subject ID we're still nested and it will maintain that. And keep us in this area until we go back and pick a different subject and navigate down the tree again. Now we've done it for pages so that pages are nested in subjects. On your own I want you to try nesting the sections into the page. It works exactly the same way. You don't have to maintain the subject id as you navigate through the section section because it's findable by looking at the page object.
It's up to you, you can keep passing it around if you want. Or you can just pass around the page that we're on and know that whenever you need to, you can look at that page to find out its subject ID. I think not only does nesting these pages make for a better user experience, I think it's also good practice to get used to passing around and maintaining parameters in your URLs like this Once you have your sections nested inside your pages, meet me in the next movie so we can talk about the effect that this nesting has on our sort positions.
- Why use Ruby on Rails?
- Installing Ruby on Rails on Mac and Windows
- Rendering templates and redirecting requests
- Generating and running database migrations
- Creating, updating, and deleting records
- Understanding association types
- Using layouts, partials, and view helpers
- Incorporating assets using asset pipeline
- Validating form data
- Authenticating users and managing user access
- Architecting RESTful applications
- Debugging and error handing