Lab 4: Using Models
Before we begin, it is time to find a new person to pair with. Please find a new pair — someone you haven’t worked with yet.
In this lab, we will use ‘models’ in rails to store structured data persistently (aka long-term).
Create a new rails application and configure it to access the database
As usual, we begin by creating a new rails application. However, this time, we will use an additional parameter to tell it we will be using a MySQL database:
$ new_repo lab4 $ rails new lab4 -d mysql $ cd lab4
This week we have one additional step: we need to configure this application to access the MySQL database. To do
so, open up the file
config/database.yml. You need to make three edits to each of the three environments.
- You need to add your username as a prefix on the name of the database. So I would replace
- You need to fill in your username in the username field. I would do
- You need to fill in your password
You need to do this one for each of the three environments. In the end, your database file should look something like this (with the correct username and passwords filled in):
development: adapter: mysql2 encoding: utf8 reconnect: false database: rwash_lab4_development pool: 5 username: rwash password: ****** socket: /var/run/mysqld/mysqld.sock # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: adapter: mysql2 encoding: utf8 reconnect: false database: rwash_lab4_test pool: 5 username: rwash password: ****** socket: /var/run/mysqld/mysqld.sock production: adapter: mysql2 encoding: utf8 reconnect: false database: rwash_lab4_production pool: 5 username: rwash password: ****** socket: /var/run/mysqld/mysqld.sock
Once you’ve edited and saved this file, we need to do 2 things. First, we need to create the database. We do this with the command
$ rake db:create
As long as no error messages were printed, then the command was successful. To test the connection to the database to make sure it works, we can use the command
$ rake db:version
which should return a current version of 0.
Don’t forget to check in your changes to the git repository. You should always do this periodically so you don’t lose anything:
$ git add . $ git commit $ git push origin master
We might as well give our pair access right now also:
$ repo_add_user lab4 <pair_username>
Create a New Resource
We will ask rails to generate a new resource. A resource consists of a model to store information in the database,
a controller to access and process that information, and a set of views to display that information. To create a
resource, we use the command
rails generate resource. Let us begin by creating a
$ rails generate resource Person
This created a couple things. First, it created a migration – a description of what changes should be made to the database. It also created a model file and a controller file. We will begin by looking at the migration.
We need to add the structure of our Person model to the migration. First, we want to add their name. A person
has two parts: a first name and a last name. So we need to add two fields to the person model. We do this in the file
db/migrate/2012......_create_people.rb. All those numbers in the filename actually are the current date and
time – 2012/02/… We should modify the file to add two strings:
class CreatePeople < ActiveRecord::Migration def change create_table :people do |t| t.string :first_name t.string :last_name t.timestamps end end end
Now that we’ve specified the database structure, we need to actually create the table in the database to store people in. To do that, we run the command
$ rake db:migrate
Periodically check in your changes:
$ git status $ git add . $ git commit $ git push
Look at Model
In addition to the migration, the model we just created is stored in the file
app/models/person.rb. Look in
that file. It should be almost completely empty, containing just a class declaration:
class Person < ActiveRecord::Base end
This file does a lot of work already. Because it inherits from
ActiveRecord::Base, it will automatically look at the
database we’ve created and structure itself appropriately.
Create a New Controller
When we generated our resource above, the generator also created a new controller for us. That was nice of it. But, right now, the controller doesn’t do anything. We need to add our custom business logic code to this controller so that it does something useful.
To do this, we need to add three actions to this controller. First, we will add a
new action for displaying
the new person form. This action is similar to the
input action we created last week. Second, we add a
create action that the form gets submitted to. This action is similar to the
output action we created
last week, but instead of printing out the result, we want to save the data in the form to the database. Finally, we
will add an
index action for listing all the current people in the database. (
index is the computer
term for a listing of something.)
To start, we first need to add empty actions to the controller
class PeopleController < ApplicationController def new @person = Person.new end def create end def index end end
Note that I added a little bit of code in the
new action. This code creates a blank new Person object. This
object is not actually saved to the database until you run the
Look at Routes
Whenever you create new actions in a controller, you need to make sure that there is a route that allows the user
to access that action. If you go look at your
config/routes.rb file, you will find that the generator added
one line to that file already:
This line looks very different from our
match lines we’ve seen before. That’ OK; this line actually does a LOT
for us. It actually creates seven standard routes. To see the routes, go to the command line and run the
$ rake routes
The output should look like this:
Prefix Verb URI Pattern Controller#Action people GET /people(.:format) people#index POST /people(.:format) people#create new_person GET /people/new(.:format) people#new edit_person GET /people/:id/edit(.:format) people#edit person GET /people/:id(.:format) people#show PATCH /people/:id(.:format) people#update PUT /people/:id(.:format) people#update DELETE /people/:id(.:format) people#destroy
As you can see, this list seven different actions (on the right hand side) that already have routes created for them.
We will only use 3 of them today:
create. Note the URLs that were created:
/people goes to the
index action, and
/people/new goes to the
new action. (Also,
if you POST a form to the
/people url, then it will go to the
create action.) It looks like rails
already created our routes for us, so we can move on to creating the views.
New Person View
Whenever we create new actions in a controller, we should also need to create the associated view files. But in this
case, we only need views for
create doesn’t display anything.
We will begin by creating the
new view. Remembering the lessons from the last few weeks, this view will be
To create a new person, we should create a form to do this, much like last week. But we can take advantage of some built-in rails magic to make this easy:
form_for(@person) do |f|
- Creates a new form specifically for the object specified
Lets create the following view; it should look similar to, but not exactly the same, as the forms you created last week:
<h1>New Person</h1> <%= form_for(@person) do |f| %> First Name: <%= f.text_field :first_name %><br /> Last Name: <%= f.text_field :last_name %><br /> <%= f.submit %> <% end %>
form_for line creates a new form, but also specifies that this form is specifically for the
model, and uses the
@person object for values. Note that when this form is submitted, it will automatically go
Check your work. Run a server and go to
Create the New Person Object
Next, we need to fill in the
create action that actually creates a new Person object and saves it to the
database. There are three steps to creating a new person object.
First, we need to tell rails which parameters to expect from the form. The data from the form comes in an automatic
params. We can call the function
.permit() on it to tell rails to allow specific values from the
@params = params.require(:person).permit(:first_name, :last_name)
Second, we need to create a new
Person object with the information from the form:
@person = Person.new(@params)
This will create a new Person object and fill in the values that were in the form that was submitted. However, it isn’t saved to the database yet. So the third step is to save to the database:
Finally, we want to then redirect the user to the full list of people. To do that, we will use the
redirect_to function. Because we are redirecting the user, we don’t need a view page for this action.
- Automatically redirects the user to a different controller and action.
So, the final
create action (which belongs in the controller) should look like this:
def create @params = params.require(:person).permit(:first_name, :last_name) @person = Person.new(@params) @person.save redirect_to(people_url) end
Displaying a List of People
Finally, we want to have a view that displays a full list of all the people in the database. To do this, we will create
index action. The first thing we need to do is retrieve the list of all the Persons in the database. To do
this, we use the
all function on the model. Here is the source to the
index action in the
def index @people = Person.all end
This function will look through the database and retrieve a list of every name that anyone has entered, and put that
list in an array called
Next, we need to create the associated view page. On this view page, we will use the
.each function to loop
through all the names and print them out:
<h1> List of People </h1> <ul> <% @people.each do |person| %> <li> <%= person.last_name %>, <%= person.first_name %> </li> <% end %> </ul> <%= link_to "Add a new person to the database", new_person_url %>
This view page uses
@people.each to loop through all the people in the array. Each person will be filled into
person variable, and then the block (the part between the
end) will be run.
That block prints out the person’s name, last name first, in an HTML list element.
Finally, this view page contains a link (using the
link_to function we discussed earlier) to add a new person
to the database.
If you are so interested, you can also sort the results results from the database. In the controller, when you run the
all function, you can specify an additional parameter that tells rails how to sort the data. So your
list action will look like this:
def index @people = Person.order(:last_name).all end
Check your work, and save it in git
Now, we need to check everything and make sure it works. Really, you should be doing this all along. But you should
definitely do it now. Run the rails server (
rails server --port=xxxx) and enter the url in your web browser.
Remember that you want to go to
/people – so, the URL will look something like this:
Check and make sure everything works correctly. But first, what does it mean to work correctly? What should it do? Talk with your partner to figure out what the system should be able to do. Then try to see if it works; use the system and see if you can actually do what you think you should be able to do.
Once you are satisfied that everything works as it should, you should check the changes into git:
$ git add . $ git commit $ git push
For the exercise, swap pairs. The person who was driving should become the navigator, and the navigator should drive when doing the exercise. You are still doing all of the work together, as a pair; just a different person is driving.
Don’t forget to have the new driver download a copy of the git repository:
$ git clone firstname.lastname@example.org:<username>/lab4
Make sure that everything works for the new driver before going forward.
Exercise: Create a Student Model, Controller, and View
For this exercise, you should create a new resource (model+controller+views):
Student. This model should store the same
information as the previous lab’s contained about students:
- Year In School
In the controller, you should have the same three actions:
new should display a form for adding a new student to the database. The form should submit to
create, which should add the student info to the database. And
index should display a full list of
all the students in the database. The
index page should also contain a link to the
Mistakes in the Database
One of the big challenges here is that once you have run
rake db:migrate, the database has been updated,
permanently. If you go back and edit your old migration files, they won’t be able to change the database anymore. If
you made a mistake in your migration and ran the
rake db:migrate command, then that change is permanent.
The easy way to fix this is to use the command
rake db:rollback. This rolls the database back to a previous version.
You can run it multiple times to undo multiple migrations. However, not that this will cause you to lose any data in
the database. Once you’ve rolled the database back, you can edit your migration and re-run
rake db:migrate to
The better way to fix it doesn’t cause you to lose data. Instead, you have to use a new migration. To do this, run this command:
$ rails generate migration fix_people
(of course, you can name the migration whatever you want; just make it informative.)
Once you create the blank migration, then you can put your database changing code in there. To change an existing
table, you can use the
change_table function and block:
change_table :products do |t| t.rename :frist_name, :first_name end
Don’t forget to run
rake db:migrate to actually update the database. Remember, migrations are like
instructions for creating the database; you actually need to tell the computer to execute those instructions to get the
database how you want it.