The majority of Lab 6 was explained in class. If you missed class or have questions about the material we covered, please attend office hours or email me. The following hints/tips are intended to supplement the material from class, not restate it.
The code for the "email" client that we wrote in class can be viewed here.
For Lab 6, you will be adding an additional User model to your application and creating a relation between your TodoItem model and the new model. Here is the overall outline of how to do this:
users
and a new column in the todo_items
table called user_id
users
tableEach step is explained in more detail below:
If you remember from week 4, the way that we define the database for our app is by writing ActiveRecord migrations. The skeleton file for an ActiveRecord migration is created by running
rake db:create_migration NAME=some_descriptive_name
Tables are created within this file with the create_table
block (see the end of section 4.2 to review this). You should be able to create a migration to add a users
table to your app using what you learned in week 4.
The next step is to modify our existing todo_items
table. This is also done with an ActiveRecord migration, but instead of using the create_table
method, we'll be using the change_table
method. Here's an example:
#db/migrate/20141024234850_add_user_id_to_todo_items.rb
class AddUserIdToTodoItems < ActiveRecord::Migration
def change
change_table :todo_items do |t|
t.integer :user_id
end
end
end
Now is where we would normally run rake db:migrate
to apply the new migrations to our database. Unfortunately, a limitation of the SQLite database engine that our app is using in development mode is that it cannot change existing tables, so our migrations would fail. Instead, we'll delete our old database and re-create it from scratch. In the terminal, this looks like this:
rm db/development.db
rake db:migrate
If you want to delete your database on Heroku, you can use the pg:reset
command to reset your default database DATABASE_URL
. It will ask you to confirm this action by typing the name of your app at the prompt.
heroku pg:reset DATABASE_URL
You'll need to add a new model for your users table. For a refresher on ActiveRecord models, see section 4.3.
You'll then need to set up belongs_to
and has_many
relations between your two models. We covered this in class - you may also find the Rails Guide on Associations helpful.
Now that we have nested resource (i.e. we have data that belongs to other data), we can't get away with just one or two pages anymore. Fortunately, Sinatra provides a helpful mechanism for dynamic routing with wildcards. URL segments that start with a colon will act as wildcards, and will be captured and added to the params hash. Here is an example:
get '/users/:name' do
@user = User.find_by(name: params[:name])
erb :user_list
end
# this will match
# /users/foo
# /users/bar
#
# this will NOT match
# /users/foo/
# /users/foo/bar
Note that the wildcard can be any arbitrary string as long as it's a valid Ruby symbol.
get '/users/:unicorn' do
@user = User.find_by(name: params[:unicorn])
erb :user_list
end
Will work just as well as the example above.
You can use wildcards in any kind of route, including post
.
You will need to modifying your existing routes and views that deal with todo items so that they are aware of the fact that todo items are now owned by users. For example, instead of
post '/' do
TodoItem.create(params)
end
You will need to do something like
post '/:user_id/create_item' do
User.find(params[:user_id]).todo_items.create(params)
redirect "/#{params[:user_id]}"
end
Or
post '/:user_id/create_item' do
@user = User.find(params[:user_id])
TodoItem.create(user: @user, description: params[:description], due: params[:due])
redirect "/#{params[:user_id]}"
end
You will then need to update your form'saction
attribute in your todo list view to reflect the new URL it needs to call!
This lab does not require a lot of coding (it's possible to make all the required changes in ~30 minutes), but it does require you to have a solid conceptual understanding of nearly everything that we have covered in the course so far. If you find yourself struggling with something you need to do for this lab, make sure you understand why you need to do it. Again, I am always available to help via email (if you're getting a specific error message, make sure to include a screenshot!).