Now that we have movies stored in the database and a Movie model that gives us access to those movies, it's time to connect the model to the rest of our application. The goal is to end up with a movie listing page that shows the movie information that's in the database. It's a quick exercise that puts everything together to complete the MVC triad, like so:
So let's get right to it...
1. Connect Model and Controller
We'll start by bringing the model into the mix so the controller has less responsibilities.
As a reminder of where things stand, jump back into your browser and go to the movie listing page (http://localhost:3000/movies). You should see three movie titles. Recall that we hard-coded these titles in an array in the index action of the MoviesController, like so:
def index @movies = ["Iron Man", "Superman", "Spider-Man"] end
Now we want to arrange things so that the array contains Movie objects that reflect the movies in the database.
indexaction to fetch all the movies from the database. Assign the resulting array to the @movies instance variable.
Notice there's no need to require the Movie class as you'd need to do in a typical Ruby program. Rails auto-loads files in certain directories, including the models directory.
Then refresh the movie listing page and you should see something like this:
#<Movie:0x007f9e341d03b0> #<Movie:0x007f9e34167130> #<Movie:0x007f9e34165dd0>
That's not quite what we're aiming for, but it's a good start. What we're seeing is the result of calling the default to_s method on a Movie object. Where's that being called? Look back in the index.html.erb view template and you'll see this line:
<%= movie %>
We're asking ERb to display the value of the movie object. To do that, ERb implicitly calls the object's to_s method which returns that cryptic-looking string. This is progress! It means we're actually dealing with Movie objects now, not just movie title strings.
2. Update the Movie Listing
Now that the @movies array contains actual Movie objects, let's update the movie listing page to show each movie's attributes.
Change the index.html.erb view template to display the values for each movie's title, rating, and total gross. Here's the output you're shooting for:
Iron Man (PG-13): $585,366,247 Superman (PG): $300,451,603 Spider-Man (PG-13): $825,025,036
Now your movie listing should dynamically show what's in the database. That means you can create, update, or delete movies in the database and the movie listing page will change accordingly.
Give it a whirl! Hop back into a Rails console session and use what you learned in the previous exercise to add, update, or delete movies. Then refresh your browser and you should see the movie listing change accordingly.
Then, just to show off a little, let's format the total gross amount as currency. Formatting numbers as currency is so common that Rails has a built-in view helper method called number_to_currency. If you look at the documentation for this helper method, you'll see that it takes a number and some options. The documentation also includes some helpful examples.
Go ahead and give it a try! Use the precision option to remove the cents from the total gross value.
We'll look at helpers in more detail in a future exercise.
We've covered a number of commands and conventions so far, and now might be a good time to download the following cheat sheets for quick reference as you proceed through the rest of the course:
Rails Cheats PDF: A cheat sheet of Rails commands and methods used throughout the course.
Rails Conventions PDF: An overview of common Rails conventions.
The full solution for this exercise is in the
connecting-mvc directory of the code bundle.
Learning a new web development framework can feel a bit like learning a foreign language. Here's a bonus exercise to help you practice your new skills.
The ________ connects the requested URL to the appropriate code in the controller.
Controllers and models share two similar characteristics. They are both Ruby ________ and they both _________ capabilities from a parent class.
Are controller names singular or plural?
Are model names singular or plural?
Are database table names singular or plural?
The model gets its power to create, read, update, and delete objects not by magic, but because it __________ from the _________________ class.
An _________ is simply a Ruby method defined inside a controller class.
A controller action passes data to the view via ___________ ____________.
A typical _____ template is a mixture of ______ tags and _____ tags.
Which ERb tag runs the Ruby code and substitutes the result back into the template: <%= %> or <% %>?
Now you have a model, view, and controller all working in harmony. Each component has its own responsibilities:
The controller acts as a middleman. With one hand, it asks the model for application data (movies in this case) and assigns the data to instance variables. With the other hand it tells a view template to display the data in a view. Notice that the controller doesn't tell the model or view how to do their jobs.
The model provides convenient access to application-level data. In this case, our Movie model is connected to a database table that contains movie information. The model completely encapsulates the lower-level details of how each row of the database table is translated into a usable object. The model isn't concerned with how the data will be used. Models can also define business logic (behavior) which we'll look at a bit later.
The view is simply the presentation of data in an arbitrary format. In this case we used a view template to generate an HTML view. The view doesn't concern itself with how the data it's displaying was assembled.
Here's the thing: It's easy to start adding code to a Rails project and impress your manager with the sheer speed of Rails development. But before you put your hands on the keyboard, it's important to think about where to add the code. Is it a model, view, or controller concern? Because if you start mixing the MVC responsibilities, then you end up with an application that can be very difficult to change down the road. And since change is inevitable, it's best if we're prepared for it. So as we move forward with adding more features, we'll need to be mindful of separating the model, view, and controller concerns.
And on that note, in the next exercise we'll add a few more attributes to our Movie model. That change will force us to think through the parts of MVC that are affected.