Migrations Lab - Solution

This is related to the lesson on migrations.

There are a several steps in this lab.  First we'll add the Activity model and corresponding database table.

1. Generate the model and migration files.  In terminal, run:

rails generate model Activity

2. Check out the generated files:

  • app/models/activity.rb
  • db/migrate/*_create_activities.rb

3. Add the table columns into the migration file:

t.integer :salesperson_id
t.integer :contact_id
t.string :note

The Activity model is a join model between Salesperson and Contact (based on our domain model).  To support that relationship, the activities table needs foreign keys for salesperson_id and contact_id.  It also needs a note column to save what type of activity it was.

4. Execute the migration file to create the table.  In terminal, run:

rails db:migrate

Now that the table exists, we can formalize the associations with code.

A salesperson might call a contact, email a contact, meet with a contact, etc.  So a salesperson has many activities; likewise a contact has many activities.

In the Salesperson model (app/models/salesperson.rb), add the association code:

class Salesperson < ApplicationRecord
  has_many :activities
end

Same for the Contact model (app/models/contact.rb):

class Contact < ApplicationRecord
  has_many :activities
end

And last, we write the inverse associations.  Each individual activity only has one salesperson and one contact - for example, a specific call is between 1 salesperson and 1 contact.  So that Activity model has the belongs_to association:

In the Activity model (app/models/activity.rb), add the association code:

class Activity < ApplicationRecord
  belongs_to :contact
  belongs_to :salesperson
end

5. Insert 2 activities into the activities table.  This is dependent on their already being records in the associated tables.

brian = Salesperson.where({last_name: "Eng", first_name: "Brian"})[0]
contact = Contact.where({first_name: "Tim", last_name: "Cook"})[0]
values = {
  salesperson_id: brian.id,
  contact_id: contact.id,
  note: "Grabbed tacos"
}
activity = Activity.new(values)
activity.save

ben = Salesperson.where({last_name: "Block", first_name: "Ben"})[0]
contact = Contact.where({first_name: "Elon", last_name: "Musk"})[0]
values = {
  salesperson_id: ben.id,
  contact_id: contact.id,
  note: "Liked a tweet"
}
activity = Activity.new(values)
activity.save

6. Loop through the salespeople and display their activities and related contacts.  Something like this:

Brian Eng
Grabbed tacos - Tim Cook

Ben Block
Liked a tweet - Elon Musk

First get all the salespeople rows:

salespeople = Salesperson.all

Next loop through them and display the salesperson name:

for salesperson in salespeople
    puts "#{salesperson.first_name} #{salesperson.last_name}"
end

For each salesperson, loop through their activities and display the activity and the associated contact for the activity:

for salesperson in salespeople
  puts "#{salesperson.first_name} #{salesperson.last_name}"

  activities = salesperson.activities
  for activity in activities
    contact = activity.contact
    puts "#{activity.note} - #{contact.first_name} #{contact.last_name}"
  end
end