Routes: Show Page
As our app now stands, we have one page that lists all of the movies in the database. When we visit /movies, the index action runs and fetches all the movies from the database. Then it renders the index.html.erb template which generates an HTML list of movies and sends it back to the browser. That makes for a nice summary page.
In this exercise we'll create the second page of our app. When we visit /movies/1, for example, we want to see the details for that particular movie. By convention, Rails calls this the "show" page. To make that work, we need to do three things:
Add a generic route to handle requests for /movies/1, /movies/2, /movies/3, and so on.
Define a show action in the MoviesController that finds the movie with the id specified in the URL.
Create a show.html.erb template that generates HTML to display the movie's details.
If you're new to working with MVC, keeping everything in your head can be tricky. So, here's a visual of our objective:
1. Show One Movie
Again, we'll work through this from the outside in, using the error messages to light our path forward.
Start by browsing to http://localhost:3000/movies/1 and you should get the following error:
Routing Error No route matches [GET] "/movies/1"
Remember how to resolve this error? Add a route to the config/routes.rb file that maps GET requests for movies/1 to the show action of the movies controller. Don't worry about supporting other movie ids for now. We'll follow the literal error and work our way back to a more generic solution once we have the basic flow down.
Refresh your browser (you're still accessing http://localhost:3000/movies/1) and this time you should get a different error message:
Unknown action The action 'show' could not be found for MoviesController
That's your cue—and you know exactly what to do next! Define the show action such that it finds the movie in the database that has a primary key (id) of 1 and assigns it to an instance variable named @movie.
Refresh your browser again and—you probably anticipated it— we're missing something:
No template for interactive request MoviesController#show is missing a template...
Remember, unless we tell it otherwise, after running an action Rails will always try to find a view template using a naming convention. In this case, the name of the action is show, and it's in the MoviesController class, so Rails tries to render the app/views/movies/show.html.erb view template file.
Create a file named show.html.erb in the app/views/movies directory. Inside that file, start by simply displaying the movie's title to get confidence that the correct movie is being fetched from the database.
Refresh and you should see the movie title! That tells us we have the model, view, and controller happily connected.
Now update the show.html.erb template to display all the movie's information. Keep it simple by putting each attribute in a paragraph tag. In terms of helper methods, we don't want to truncate the movie description on this page. However, on this page we do want to display the movie rating and year it was released. (Remember, we removed those movie attributes from the movie listing page.) Since we went to the trouble of creating the total_gross and year_of view helpers in a previous exercise, we might as well call those helpers here.
Once you get a basic show page working, go ahead and copy in the version in the answer. It uses HTML elements and class names that trigger the styles in our custom.scss stylesheet.
That's a great start!
2. Show Any Movie
Now that we have the MVC flow working, let's make this more generic.
Browse to http://localhost:3000/movies/2 and you should get the following error:
Routing Error No route matches [GET] "/movies/2"
We knew that would happen because we only added a route for movies/1, and that route doesn't match this request. At this point we could add another route to handle movies/2, but clearly we need to make this more dynamic. The route needs to support a variable number of movie ids.
Update the route to match requests for showing any movie.
Now you should be able to browse to any of these URLs without getting any errors:
There's just one problem: All of those pages show the details for the first movie! Fix that by updating the show action to use the number at the end of the URL to find the movie in the database.
Now try visiting all three URLs above and you should see the matching movie's details.
Great—now we have our "show" page implemented!
The full solution for this exercise is in the
show-page directory of the code bundle.
This exercise was a good opportunity to take a round trip back through the entire MVC cycle. Now we have two different paths through our application: /movies shows all the movies and /movies/:id shows the details of any single movie. You probably noticed that adding the second path involved the same high-level steps as the first:
add a route
define an action
create a template
You'll end up following those same three steps over and over again as you develop Rails apps. It's the recipe for accepting requests and generating responses. The details vary depending on how you want the request to be handled, and we'll see more examples of that in future exercises, but you can flesh out a basic flow simply by following the errors as we've done here.
Hey, now that we have two pages, it sure would be nice if we could easily navigate between them! Typing these URLs in the browser's address bar is getting kinda tedious. So in the next section we'll generate hyperlinks so we can easily navigate between pages.