Find file History
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
..
Failed to load latest commit information.
README.md

README.md

LESSON: rails-api-many-to-many


2018-07-16

OBJECTIVES

By the end of this, developers should be able to:

  • Create a many-to-many relationship with existing models.
  • Create and utilize a join table.
  • Create a new resource using scaffold.
  • Specify an inverse_of relationship.
  • Compare and contrast objects created in the join table versus those that were not.

VOCABULARY

join table: An intermediary table that connects two rows in two different tables to model a many-to-many relationship.

  • Example: recipe has many ingredients, and an ingredient belongs to many recipes. When we want to relate a specific ingredient (like salt) to many recipes (like soup, chicken, guacamole, etc), we use a join table called ingredient_recipes that allow the row for salt in the ingredients table to be associated to all the various recipes that use salt.
  • This association is done using foreign keys. In the join table, a foreign key for the one recipe and the one ingredient is what makes up the row in ingredient_recipes

NOTES

  • We started with two stand-alone resources, Book and Author. This was version 1 of the ERD. ERD and user stories are here

  • We then connected Book and Author using a one-to-many relationship. This was version 2 of the ERD.

  • Now we are going to create a many-to-many relationship that you might find in a library.

    • We are going to model the real world relationship between books, borrowers and borrowed books. We are going to call the join table Loans.
    • A row in the Loan table connects a row in the Books table and a row in the Borrowers table.
  • Walking through creating a many-to-many relationship between Book, Borrower and Loan is here

  • Creating loans join table is here

  • Adding relationship macros to rails models and testing it with curl is here

How to update your database in rails

  1. Plan your changes! Update your ERD
  2. Create the migration (bin/rails generate migration OR create a scaffold or model using a generator which also gives you a migration
    • ALWAYS use a migration to make a change to your database.
    • DO NOT edit the schema.rb by hand, or edit the database structure by hand using something like psql. This will break the rails mechanisms which track database changes and allow you to manage your database schema.
  3. Run the migration: bin/rails db:migrate
  4. Double check it worked
    • in bin/rails console
    • in schema.rb
    • in psql
    • using curl scripts

How to add data to your database in rails

  1. using the rails console (manually add records and assocate records)

  2. using seed files (bulk load example data, seed data, etc)

    • example writing seed data loading scripts and rails tasks to run these scripts: commit
  3. using curl scripts

  4. using your frontend application

Model macros

  • # ruby models contain macros to describe the relationships
    
    # app/models/book.rb
    class Book
    	 has_many :loans
    	 has_many :borrowers, through: :loans
    end
    
    # app/models/borrower.rb
    class Borrower
    	 has_many :loans
    	 has_many :books, through: :loans
    end
    
    	 # app/models/loan.rb
    class Loan
    	 belongs_to :borrower
    	 belongs_to :book
    end
    

In Rails Console

# Get multiple things back from resources
Book.first.borrowers
Book.first.loans
Borrower.first.books
Borrower.first.loans

# Get one thing back from join table
Loan.first.book
Loan.first.borrower

# these are unchanged
Author.first.books
Book.first.author

Rails Docs

has_many :through

Rails Console: Testing Book, Borrower and Loan

rails c
Running via Spring preloader in process 12290
Loading development environment (Rails 5.1.4)
[1] pry(main)> Book
=> Book(id: integer, title: string, created_at: datetime, updated_at: datetime, author_id: integer)
[2] pry(main)> Loan
=> Loan(id: integer, borrower_id: integer, book_id: integer, created_at: datetime, updated_at: datetime)
[3] pry(main)> Borrower
=> Borrower(id: integer, first_name: string, last_name: string, created_at: datetime, updated_at: datetime)
[4] pry(main)> Ingredient
=> Ingredient(id: integer, name: string, unit: string, created_at: datetime, updated_at: datetime)
[5] pry(main)> Doctor
=> Doctor(id: integer, first_name: string, last_name: string, zip_code: string, specialty: string, created_at: datetime, updated_at: datetime)
[6] pry(main)> Book.new
=> #<Book:0x00007fcdac9688a0 id: nil, title: nil, created_at: nil, updated_at: nil, author_id: nil>
[7] pry(main)> Doctor
=> Doctor(id: integer, first_name: string, last_name: string, zip_code: string, specialty: string, created_at: datetime, updated_at: datetime)
[8] pry(main)> Doctor.create({first_name: 'Nate', last_name: 'Dunn', zip_code: '02909', specialty: 'Not a doctor'})
   (0.3ms)  BEGIN
  SQL (26.9ms)  INSERT INTO "doctors" ("first_name", "last_name", "zip_code", "specialty", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id"  [["first_name", "Nate"], ["last_name", "Dunn"], ["zip_code", "02909"], ["specialty", "Not a doctor"], ["created_at", "2018-07-17 17:50:25.625034"], ["updated_at", "2018-07-17 17:50:25.625034"]]
   (18.5ms)  COMMIT
=> #<Doctor:0x00007fcdb011b5b8
 id: 1,
 first_name: "Nate",
 last_name: "Dunn",
 zip_code: "02909",
 specialty: "Not a doctor",
 created_at: Tue, 17 Jul 2018 17:50:25 UTC +00:00,
 updated_at: Tue, 17 Jul 2018 17:50:25 UTC +00:00>
[9] pry(main)> doctor = Doctor.new
=> #<Doctor:0x00007fcdac9dec58 id: nil, first_name: nil, last_name: nil, zip_code: nil, specialty: nil, created_at: nil, updated_at: nil>
[10] pry(main)> doctor.first_name = 'Arjun'
=> "Arjun"
[11] pry(main)> doctor.last_name = 'Ray'
=> "Ray"
[12] pry(main)> exit
dkirschner@63.95.30.172.o.wireless.uri.edu: rails-api-campus-server (tutorial-danny-tuesday)* $ rails c
Running via Spring preloader in process 12447
Loading development environment (Rails 5.1.4)
[1] pry(main)> book = Book.create(title: 'Brave New World')
   (0.2ms)  BEGIN
   (0.5ms)  ROLLBACK
=> #<Book:0x00007fcdabfeb958 id: nil, title: "Brave New World", created_at: nil, updated_at: nil, author_id: nil>
[2] pry(main)> book = Book.create({title: 'Brave New World'})
   (0.2ms)  BEGIN
   (0.3ms)  ROLLBACK
=> #<Book:0x00007fcdad35d860 id: nil, title: "Brave New World", created_at: nil, updated_at: nil, author_id: nil>
[3] pry(main)> book.errors
=> #<ActiveModel::Errors:0x00007fcdad1ba8f0
 @base=#<Book:0x00007fcdad35d860 id: nil, title: "Brave New World", created_at: nil, updated_at: nil, author_id: nil>,
 @details={:author=>[{:error=>:blank}]},
 @messages={:author=>["must exist"]}>
[4] pry(main)> author = Author.create(given_name:'Aldous', family_name:'Huxley')
ActiveModel::UnknownAttributeError: unknown attribute 'given_name' for Author.
from /Users/dkirschner/.rvm/gems/ruby-2.5.0/gems/activemodel-5.1.4/lib/active_model/attribute_assignment.rb:48:in `_assign_attribute'
[5] pry(main)> Author
=> Author(id: integer, first_name: string, last_name: string, created_at: datetime, updated_at: datetime)
[6] pry(main)> author = Author.create(first_name:'Aldous', last_name:'Huxley')
   (0.2ms)  BEGIN
  SQL (13.9ms)  INSERT INTO "authors" ("first_name", "last_name", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"  [["first_name", "Aldous"], ["last_name", "Huxley"], ["created_at", "2018-07-17 18:02:14.538019"], ["updated_at", "2018-07-17 18:02:14.538019"]]
   (13.2ms)  COMMIT
=> #<Author:0x00007fcdabf8b8a0
 id: 1,
 first_name: "Aldous",
 last_name: "Huxley",
 created_at: Tue, 17 Jul 2018 18:02:14 UTC +00:00,
 updated_at: Tue, 17 Jul 2018 18:02:14 UTC +00:00>
[7] pry(main)> book = Book.create({title: 'Brave New World', author: author})
   (0.4ms)  BEGIN
  SQL (21.6ms)  INSERT INTO "books" ("title", "created_at", "updated_at", "author_id") VALUES ($1, $2, $3, $4) RETURNING "id"  [["title", "Brave New World"], ["created_at", "2018-07-17 18:03:21.281736"], ["updated_at", "2018-07-17 18:03:21.281736"], ["author_id", 1]]
   (0.6ms)  COMMIT
=> #<Book:0x00007fcdad771208
 id: 1,
 title: "Brave New World",
 created_at: Tue, 17 Jul 2018 18:03:21 UTC +00:00,
 updated_at: Tue, 17 Jul 2018 18:03:21 UTC +00:00,
 author_id: 1>
[8] pry(main)> author
=> #<Author:0x00007fcdabf8b8a0
 id: 1,
 first_name: "Aldous",
 last_name: "Huxley",
 created_at: Tue, 17 Jul 2018 18:02:14 UTC +00:00,
 updated_at: Tue, 17 Jul 2018 18:02:14 UTC +00:00>
[9] pry(main)> author.books.create(title: 'Some Other SciFi Book')
   (0.2ms)  BEGIN
  SQL (0.5ms)  INSERT INTO "books" ("title", "created_at", "updated_at", "author_id") VALUES ($1, $2, $3, $4) RETURNING "id"  [["title", "Some Other SciFi Book"], ["created_at", "2018-07-17 18:03:43.626479"], ["updated_at", "2018-07-17 18:03:43.626479"], ["author_id", 1]]
   (6.0ms)  COMMIT
=> #<Book:0x00007fcdac9823e0
 id: 2,
 title: "Some Other SciFi Book",
 created_at: Tue, 17 Jul 2018 18:03:43 UTC +00:00,
 updated_at: Tue, 17 Jul 2018 18:03:43 UTC +00:00,
 author_id: 1>
[10] pry(main)> author.books << Book.create(title: 'Another book')
   (0.2ms)  BEGIN
   (0.3ms)  ROLLBACK
   (0.2ms)  BEGIN
  SQL (0.6ms)  INSERT INTO "books" ("title", "created_at", "updated_at", "author_id") VALUES ($1, $2, $3, $4) RETURNING "id"  [["title", "Another book"], ["created_at", "2018-07-17 18:05:52.806020"], ["updated_at", "2018-07-17 18:05:52.806020"], ["author_id", 1]]
   (6.3ms)  COMMIT
  Book Load (6.8ms)  SELECT "books".* FROM "books" WHERE "books"."author_id" = $1  [["author_id", 1]]
=> [#<Book:0x00007fcdb01353c8
  id: 1,
  title: "Brave New World",
  created_at: Tue, 17 Jul 2018 18:03:21 UTC +00:00,
  updated_at: Tue, 17 Jul 2018 18:03:21 UTC +00:00,
  author_id: 1>,
 #<Book:0x00007fcdac9823e0
  id: 2,
  title: "Some Other SciFi Book",
  created_at: Tue, 17 Jul 2018 18:03:43 UTC +00:00,
  updated_at: Tue, 17 Jul 2018 18:03:43 UTC +00:00,
  author_id: 1>,
 #<Book:0x00007fcdb0862948
  id: 3,
  title: "Another book",
  created_at: Tue, 17 Jul 2018 18:05:52 UTC +00:00,
[12] pry(main)> Author.all
  Author Load (0.6ms)  SELECT "authors".* FROM "authors"
=> [#<Author:0x00007fcdabe3c9b8
  id: 1,
  first_name: "Aldous",
  last_name: "Huxley",
  created_at: Tue, 17 Jul 2018 18:02:14 UTC +00:00,
  updated_at: Tue, 17 Jul 2018 18:02:14 UTC +00:00>]
[13] pry(main)> Author.find_by(first_name: 'Aldous')
  Author Load (0.4ms)  SELECT  "authors".* FROM "authors" WHERE "authors"."first_name" = $1 LIMIT $2  [["first_name", "Aldous"], ["LIMIT", 1]]
=> #<Author:0x00007fcdb0297860
 id: 1,
 first_name: "Aldous",
 last_name: "Huxley",
 created_at: Tue, 17 Jul 2018 18:02:14 UTC +00:00,
 updated_at: Tue, 17 Jul 2018 18:02:14 UTC +00:00>
[14] pry(main)> Loan.all
  Loan Load (13.3ms)  SELECT "loans".* FROM "loans"
=> []
[15] pry(main)> book = Book.last
  Book Load (0.4ms)  SELECT  "books".* FROM "books" ORDER BY "books"."id" DESC LIMIT $1  [["LIMIT", 1]]
=> #<Book:0x00007fcdb0814658
 id: 3,
 title: "Another book",
 created_at: Tue, 17 Jul 2018 18:05:52 UTC +00:00,
 updated_at: Tue, 17 Jul 2018 18:05:52 UTC +00:00,
 author_id: 1>
[16] pry(main)> borrower = Borrower.create(first
[16] pry(main)> Borrower
=> Borrower(id: integer, first_name: string, last_name: string, created_at: datetime, updated_at: datetime)
[17] pry(main)> book = Book.las
[17] pry(main)> borrower = Borrower.create(first_name: 'Nate', last_name: 'Dunn')
   (0.2ms)  BEGIN
  SQL (17.9ms)  INSERT INTO "borrowers" ("first_name", "last_name", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"  [["first_name", "Nate"], ["last_name", "Dunn"], ["created_at", "2018-07-17 18:09:11.342666"], ["updated_at", "2018-07-17 18:09:11.342666"]]
   (0.5ms)  COMMIT
=> #<Borrower:0x00007fcdac0f79f0
 id: 1,
 first_name: "Nate",
 last_name: "Dunn",
 created_at: Tue, 17 Jul 2018 18:09:11 UTC +00:00,
 updated_at: Tue, 17 Jul 2018 18:09:11 UTC +00:00>
[18] pry(main)> book
=> #<Book:0x00007fcdb0814658
 id: 3,
 title: "Another book",
 created_at: Tue, 17 Jul 2018 18:05:52 UTC +00:00,
 updated_at: Tue, 17 Jul 2018 18:05:52 UTC +00:00,
 author_id: 1>
[19] pry(main)> borrower
=> #<Borrower:0x00007fcdac0f79f0
 id: 1,
 first_name: "Nate",
 last_name: "Dunn",
 created_at: Tue, 17 Jul 2018 18:09:11 UTC +00:00,
 updated_at: Tue, 17 Jul 2018 18:09:11 UTC +00:00>
[20] pry(main)> book.borrowers
  Borrower Load (1.3ms)  SELECT "borrowers".* FROM "borrowers" INNER JOIN "loans" ON "borrowers"."id" = "loans"."borrower_id" WHERE "loans"."book_id" = $1  [["book_id", 3]]
=> []
[21] pry(main)> book.borrowers << borrower
   (0.2ms)  BEGIN
  SQL (1.5ms)  INSERT INTO "loans" ("borrower_id", "book_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"  [["borrower_id", 1], ["book_id", 3], ["created_at", "2018-07-17 18:10:02.511772"], ["updated_at", "2018-07-17 18:10:02.511772"]]
   (5.2ms)  COMMIT
=> [#<Borrower:0x00007fcdac0f79f0
  id: 1,
  first_name: "Nate",
  last_name: "Dunn",
  created_at: Tue, 17 Jul 2018 18:09:11 UTC +00:00,
  updated_at: Tue, 17 Jul 2018 18:09:11 UTC +00:00>]
[22] pry(main)> Loan.last
  Loan Load (0.3ms)  SELECT  "loans".* FROM "loans" ORDER BY "loans"."id" DESC LIMIT $1  [["LIMIT", 1]]
=> #<Loan:0x00007fcdabcd5b88
 id: 1,
 borrower_id: 1,
 book_id: 3,
 created_at: Tue, 17 Jul 2018 18:10:02 UTC +00:00,
 updated_at: Tue, 17 Jul 2018 18:10:02 UTC +00:00>
[23] pry(main)> Loan.last.borrower
  Loan Load (0.4ms)  SELECT  "loans".* FROM "loans" ORDER BY "loans"."id" DESC LIMIT $1  [["LIMIT", 1]]
  Borrower Load (0.3ms)  SELECT  "borrowers".* FROM "borrowers" WHERE "borrowers"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
=> #<Borrower:0x00007fcdb0357408
 id: 1,
 first_name: "Nate",
 last_name: "Dunn",
 created_at: Tue, 17 Jul 2018 18:09:11 UTC +00:00,
 updated_at: Tue, 17 Jul 2018 18:09:11 UTC +00:00>
[24] pry(main)> Loan.last.book
  Loan Load (0.5ms)  SELECT  "loans".* FROM "loans" ORDER BY "loans"."id" DESC LIMIT $1  [["LIMIT", 1]]
  Book Load (0.3ms)  SELECT  "books".* FROM "books" WHERE "books"."id" = $1 LIMIT $2  [["id", 3], ["LIMIT", 1]]
=> #<Book:0x00007fcdb03348e0
 id: 3,
 title: "Another book",
 created_at: Tue, 17 Jul 2018 18:05:52 UTC +00:00,
 updated_at: Tue, 17 Jul 2018 18:05:52 UTC +00:00,
 author_id: 1>
 

Console logs Testing Doctors, Patients and appointments

pry(main)> Patient
=> Patient(id: integer, first_name: string, last_name: string, diagnosis: string, born_on: date, created_at: datetime, updated_at: datetime, doctor_id: integer)
[43] pry(main)> Patient.create(first_name: 'Nate', last_name: 'Dunn', diagnosis: 'GA Instructor', born_on: '2000-01-01')
   (0.2ms)  BEGIN
  SQL (14.8ms)  INSERT INTO "patients" ("first_name", "last_name", "diagnosis", "born_on", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id"  [["first_name", "Nate"], ["last_name", "Dunn"], ["diagnosis", "GA Instructor"], ["born_on", "2000-01-01"], ["created_at", "2018-07-17 18:54:02.964827"], ["updated_at", "2018-07-17 18:54:02.964827"]]
   (6.3ms)  COMMIT
=> #<Patient:0x00007fcdb0058b80
 id: 1,
 first_name: "Nate",
 last_name: "Dunn",
 diagnosis: "GA Instructor",
 born_on: Sat, 01 Jan 2000,
 created_at: Tue, 17 Jul 2018 18:54:02 UTC +00:00,
 updated_at: Tue, 17 Jul 2018 18:54:02 UTC +00:00,
 doctor_id: nil>
[44] pry(main)> patient = Patient.last
  Patient Load (0.7ms)  SELECT  "patients".* FROM "patients" ORDER BY "patients"."id" DESC LIMIT $1  [["LIMIT", 1]]
=> #<Patient:0x00007fcdabf54a30
 id: 1,
 first_name: "Nate",
 last_name: "Dunn",
 diagnosis: "GA Instructor",
 born_on: Sat, 01 Jan 2000,
 created_at: Tue, 17 Jul 2018 18:54:02 UTC +00:00,
 updated_at: Tue, 17 Jul 2018 18:54:02 UTC +00:00,
 doctor_id: nil>
[45] pry(main)> patient.doctors
  Doctor Load (0.7ms)  SELECT "doctors".* FROM "doctors" INNER JOIN "appointments" ON "doctors"."id" = "appointments"."doctor_id" WHERE "appointments"."patient_id" = $1  [["patient_id", 1]]
=> []
[46] pry(main)> Doctor.all
  Doctor Load (0.5ms)  SELECT "doctors".* FROM "doctors"
=> [#<Doctor:0x00007fcdabe75ad8
  id: 1,
  first_name: "Nate",
  last_name: "Dunn",
  zip_code: "02909",
  specialty: "Not a doctor",
  created_at: Tue, 17 Jul 2018 17:50:25 UTC +00:00,
  updated_at: Tue, 17 Jul 2018 17:50:25 UTC +00:00>]
[47] pry(main)> doctor = Doctor.new(first_name: 'Dr', last_name: 'Bob', zip_code: "02901", specialty: 'Eyes')
=> #<Doctor:0x00007fcdac8fc010
 id: nil,
 first_name: "Dr",
 last_name: "Bob",
 zip_code: "02901",
 specialty: "Eyes",
 created_at: nil,
 updated_at: nil>
[48] pry(main)> doctor
=> #<Doctor:0x00007fcdac8fc010
 id: nil,
 first_name: "Dr",
 last_name: "Bob",
 zip_code: "02901",
 specialty: "Eyes",
 created_at: nil,
 updated_at: nil>
[49] pry(main)> doctor.save
   (1.2ms)  BEGIN
  SQL (13.1ms)  INSERT INTO "doctors" ("first_name", "last_name", "zip_code", "specialty", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id"  [["first_name", "Dr"], ["last_name", "Bob"], ["zip_code", "02901"], ["specialty", "Eyes"], ["created_at", "2018-07-17 18:58:44.664655"], ["updated_at", "2018-07-17 18:58:44.664655"]]
   (0.5ms)  COMMIT
=> true
[50] pry(main)> doctor.errors
=> #<ActiveModel::Errors:0x00007fcdac0ac400
 @base=
  #<Doctor:0x00007fcdac8fc010
   id: 2,
   first_name: "Dr",
   last_name: "Bob",
   zip_code: "02901",
   specialty: "Eyes",
   created_at: Tue, 17 Jul 2018 18:58:44 UTC +00:00,
   updated_at: Tue, 17 Jul 2018 18:58:44 UTC +00:00>,
 @details={},
 @messages={}>
[51] pry(main)> doctor.errors.any?
=> false
[52] pry(main)> patient
=> #<Patient:0x00007fcdabf54a30
 id: 1,
 first_name: "Nate",
 last_name: "Dunn",
 diagnosis: "GA Instructor",
 born_on: Sat, 01 Jan 2000,
 created_at: Tue, 17 Jul 2018 18:54:02 UTC +00:00,
 updated_at: Tue, 17 Jul 2018 18:54:02 UTC +00:00,
 doctor_id: nil>
[53] pry(main)> doctor
=> #<Doctor:0x00007fcdac8fc010
 id: 2,
 first_name: "Dr",
 last_name: "Bob",
 zip_code: "02901",
 specialty: "Eyes",
 created_at: Tue, 17 Jul 2018 18:58:44 UTC +00:00,
 updated_at: Tue, 17 Jul 2018 18:58:44 UTC +00:00>
[54] pry(main)> patient.doctors.push doctor
   (0.3ms)  BEGIN
  SQL (3.8ms)  INSERT INTO "appointments" ("patient_id", "doctor_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"  [["patient_id", 1], ["doctor_id", 2], ["created_at", "2018-07-17 19:01:17.707606"], ["updated_at", "2018-07-17 19:01:17.707606"]]
   (0.7ms)  COMMIT
=> [#<Doctor:0x00007fcdac8fc010
  id: 2,
  first_name: "Dr",
  last_name: "Bob",
  zip_code: "02901",
  specialty: "Eyes",
  created_at: Tue, 17 Jul 2018 18:58:44 UTC +00:00,
  updated_at: Tue, 17 Jul 2018 18:58:44 UTC +00:00>]
[55] pry(main)> Appointment.last
  Appointment Load (0.4ms)  SELECT  "appointments".* FROM "appointments" ORDER BY "appointments"."id" DESC LIMIT $1  [["LIMIT", 1]]
=> #<Appointment:0x00007fcdb0a86b98
 id: 1,
 patient_id: 1,
 doctor_id: 2,
 created_at: Tue, 17 Jul 2018 19:01:17 UTC +00:00,
 updated_at: Tue, 17 Jul 2018 19:01:17 UTC +00:00>
[56] pry(main)> Appointment.last.doctor
  Appointment Load (0.4ms)  SELECT  "appointments".* FROM "appointments" ORDER BY "appointments"."id" DESC LIMIT $1  [["LIMIT", 1]]
  Doctor Load (0.3ms)  SELECT  "doctors".* FROM "doctors" WHERE "doctors"."id" = $1 LIMIT $2  [["id", 2], ["LIMIT", 1]]
=> #<Doctor:0x00007fcdb0a44bd0
 id: 2,
 first_name: "Dr",
 last_name: "Bob",
 zip_code: "02901",
 specialty: "Eyes",
 created_at: Tue, 17 Jul 2018 18:58:44 UTC +00:00,
 updated_at: Tue, 17 Jul 2018 18:58:44 UTC +00:00>
[57] pry(main)> Appointment.last.patient
  Appointment Load (0.5ms)  SELECT  "appointments".* FROM "appointments" ORDER BY "appointments"."id" DESC LIMIT $1  [["LIMIT", 1]]
  Patient Load (0.5ms)  SELECT  "patients".* FROM "patients" WHERE "patients"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
=> #<Patient:0x00007fcdb00fb880
 id: 1,
 first_name: "Nate",
 last_name: "Dunn",
 diagnosis: "GA Instructor",
 born_on: Sat, 01 Jan 2000,
 created_at: Tue, 17 Jul 2018 18:54:02 UTC +00:00,
 updated_at: Tue, 17 Jul 2018 18:54:02 UTC +00:00,
 doctor_id: nil>
[58] pry(main)> doctor
=> #<Doctor:0x00007fcdac8fc010
 id: 2,
 first_name: "Dr",
 last_name: "Bob",
 zip_code: "02901",
 specialty: "Eyes",
 created_at: Tue, 17 Jul 2018 18:58:44 UTC +00:00,
 updated_at: Tue, 17 Jul 2018 18:58:44 UTC +00:00>
[59] pry(main)> doctor.patients
  Patient Load (0.6ms)  SELECT "patients".* FROM "patients" INNER JOIN "appointments" ON "patients"."id" = "appointments"."patient_id" WHERE "appointments"."doctor_id" = $1  [["doctor_id", 2]]
=> [#<Patient:0x00007fcdb024cfb8
  id: 1,
  first_name: "Nate",
  last_name: "Dunn",
  diagnosis: "GA Instructor",
  born_on: Sat, 01 Jan 2000,
  created_at: Tue, 17 Jul 2018 18:54:02 UTC +00:00,
  updated_at: Tue, 17 Jul 2018 18:54:02 UTC +00:00,
  doctor_id: nil>]
  

Console log from Recipe, Ingredient, Meals many-to-many lab

pry(main)> Ingredient
=> Ingredient(id: integer, name: string, unit: string, created_at: datetime, updated_at: datetime)
[2] pry(main)> Recipe
# No model / class exists! 
NameError: uninitialized constant Recipe
from (pry):2:in `<main>'
[3] pry(main)> exit
dkirschner@63.95.30.172.o.wireless.uri.edu: rails-api-campus-server (tutorial-danny-tuesday)* $ rails c
Running via Spring preloader in process 16232
Loading development environment (Rails 5.1.4)
[1] pry(main)> Recipe
# migration hasn't been run!
=> Recipe(Table doesn't exist)
[2] pry(main)> Ingredient.create(name: 'sugar', unit: 'tbsp')
   (0.2ms)  BEGIN
  SQL (17.2ms)  INSERT INTO "ingredients" ("name", "unit", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"  [["name", "sugar"], ["unit", "tbsp"], ["created_at", "2018-07-18 14:45:11.957020"], ["updated_at", "2018-07-18 14:45:11.957020"]]
   (14.5ms)  COMMIT
=> #<Ingredient:0x00007f8d4e899238
 id: 1,
 name: "sugar",
 unit: "tbsp",
 created_at: Wed, 18 Jul 2018 14:45:11 UTC +00:00,
 updated_at: Wed, 18 Jul 2018 14:45:11 UTC +00:00>
[3] pry(main)> Recipe
=> Recipe(Table doesn't exist)
[4] pry(main)> reload!
Reloading...
=> true
[5] pry(main)> Recipe
=> Recipe(id: integer, name: string, description: string, created_at: datetime, updated_at: datetime)
[6] pry(main)> Ingredient
=> Ingredient(id: integer, name: string, unit: string, created_at: datetime, updated_at: datetime)
[7] pry(main)> RecipeIngredient
NameError: uninitialized constant RecipeIngredient
from (pry):7:in `<main>'
[8] pry(main)> Meal
NameError: uninitialized constant Meal
from (pry):8:in `<main>'
[9] pry(main)> reload!
Reloading...
=> true
[10] pry(main)> Meal
=> Meal(id: integer, ingredient_id: integer, recipe_id: integer, created_at: datetime, updated_at: datetime)
[11] pry(main)> Ingredient.last
  Ingredient Load (0.7ms)  SELECT  "ingredients".* FROM "ingredients" ORDER BY "ingredients"."id" DESC LIMIT $1  [["LIMIT", 1]]
=> #<Ingredient:0x00007f8d4af8dbd8
 id: 1,
 name: "sugar",
 unit: "tbsp",
 created_at: Wed, 18 Jul 2018 14:45:11 UTC +00:00,
 updated_at: Wed, 18 Jul 2018 14:45:11 UTC +00:00>
[12] pry(main)> Ingredient.last.recipes
  Ingredient Load (0.5ms)  SELECT  "ingredients".* FROM "ingredients" ORDER BY "ingredients"."id" DESC LIMIT $1  [["LIMIT", 1]]
NoMethodError: undefined method `recipes' for #<Ingredient:0x00007f8d4c1aa578>
from /Users/dkirschner/.rvm/gems/ruby-2.5.0/gems/activemodel-5.1.4/lib/active_model/attribute_methods.rb:432:in `method_missing'
[13] pry(main)> reload!
Reloading...
=> true
[14] pry(main)> Meal
=> Meal(id: integer, ingredient_id: integer, recipe_id: integer, created_at: datetime, updated_at: datetime)
[15] pry(main)> recipe = Recipe.create(name: 'Waffles', description: 'Breakfast food')
   (0.2ms)  BEGIN
   (6.3ms)  ROLLBACK
=> #<Recipe:0x00007f8d4be884a8
 id: nil,
 name: "Waffles",
 description: "Breakfast food",
 created_at: nil,
 updated_at: nil>
[16] pry(main)> recipe.errors
=> #<ActiveModel::Errors:0x00007f8d50090cb0
 @base=
  #<Recipe:0x00007f8d4be884a8
   id: nil,
   name: "Waffles",
   description: "Breakfast food",
   created_at: nil,
   updated_at: nil>,
 @details={:user=>[{:error=>:blank}]},
 @messages={:user=>["must exist"]}>
[17] pry(main)> reload!
Reloading...
=> true
[18] pry(main)> recipe = Recipe.create(name: 'Waffles', description: 'Breakfast food')
   (0.2ms)  BEGIN
  SQL (14.2ms)  INSERT INTO "recipes" ("name", "description", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"  [["name", "Waffles"], ["description", "Breakfast food"], ["created_at", "2018-07-18 15:11:32.947846"], ["updated_at", "2018-07-18 15:11:32.947846"]]
   (5.4ms)  COMMIT
=> #<Recipe:0x00007f8d4ac465b0
 id: 1,
 name: "Waffles",
 description: "Breakfast food",
 created_at: Wed, 18 Jul 2018 15:11:32 UTC +00:00,
 updated_at: Wed, 18 Jul 2018 15:11:32 UTC +00:00>
[19] pry(main)> recipe.persisted?
=> true
[20] pry(main)> ingredient = Ingredient.create()
[20] pry(main)> Ingredient
=> Ingredient(id: integer, name: string, unit: string, created_at: datetime, updated_at: datetime)
[21] pry(main)> ingredient = Ingredient.create(name: 'flour', unit: 'cup')
   (0.3ms)  BEGIN
  SQL (0.5ms)  INSERT INTO "ingredients" ("name", "unit", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"  [["name", "flour"], ["unit", "cup"], ["created_at", "2018-07-18 15:13:31.758405"], ["updated_at", "2018-07-18 15:13:31.758405"]]
   (9.0ms)  COMMIT
=> #<Ingredient:0x00007f8d4e829780
 id: 2,
 name: "flour",
 unit: "cup",
 created_at: Wed, 18 Jul 2018 15:13:31 UTC +00:00,
 updated_at: Wed, 18 Jul 2018 15:13:31 UTC +00:00>
[22] pry(main)> meal = Meal.new(ingredient.id, recipe.id)
ArgumentError: wrong number of arguments (given 2, expected 0..1)
from /Users/dkirschner/.rvm/gems/ruby-2.5.0/gems/activerecord-5.1.4/lib/active_record/core.rb:330:in `initialize'
[23] pry(main)> meal = Meal.new({ingredient_id: ingredient.id, recipe_id: recipe.id})
=> #<Meal:0x00007f8d4be25c90 id: nil, ingredient_id: 2, recipe_id: 1, created_at: nil, updated_at: nil>
[24] pry(main)> hash = { key: 'value' }
=> {:key=>"value"}
[25] pry(main)> hash[:key]
=> "value"
[26] pry(main)> meal.persisted?
=> false
[27] pry(main)> meal.save
   (0.3ms)  BEGIN
  Ingredient Load (1.1ms)  SELECT  "ingredients".* FROM "ingredients" WHERE "ingredients"."id" = $1 LIMIT $2  [["id", 2], ["LIMIT", 1]]
  Recipe Load (0.4ms)  SELECT  "recipes".* FROM "recipes" WHERE "recipes"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
  SQL (18.6ms)  INSERT INTO "meals" ("ingredient_id", "recipe_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"  [["ingredient_id", 2], ["recipe_id", 1], ["created_at", "2018-07-18 15:17:18.807182"], ["updated_at", "2018-07-18 15:17:18.807182"]]
   (0.5ms)  COMMIT
=> true
[28] pry(main)> meal.recipe
=> #<Recipe:0x00007f8d4ec82ae8
 id: 1,
 name: "Waffles",
 description: "Breakfast food",
 created_at: Wed, 18 Jul 2018 15:11:32 UTC +00:00,
 updated_at: Wed, 18 Jul 2018 15:11:32 UTC +00:00>
[29] pry(main)> meal.ingredient
=> #<Ingredient:0x00007f8d4eca2f00
 id: 2,
 name: "flour",
 unit: "cup",
 created_at: Wed, 18 Jul 2018 15:13:31 UTC +00:00,
 updated_at: Wed, 18 Jul 2018 15:13:31 UTC +00:00>
[30] pry(main)> recipe
=> #<Recipe:0x00007f8d4ac465b0
 id: 1,
 name: "Waffles",
 description: "Breakfast food",
 created_at: Wed, 18 Jul 2018 15:11:32 UTC +00:00,
 updated_at: Wed, 18 Jul 2018 15:11:32 UTC +00:00>
[31] pry(main)> recipe.ingredients
  Ingredient Load (0.8ms)  SELECT "ingredients".* FROM "ingredients" INNER JOIN "meals" ON "ingredients"."id" = "meals"."ingredient_id" WHERE "meals"."recipe_id" = $1  [["recipe_id", 1]]
=> [#<Ingredient:0x00007f8d4e937280
  id: 2,
  name: "flour",
  unit: "cup",
  created_at: Wed, 18 Jul 2018 15:13:31 UTC +00:00,
  updated_at: Wed, 18 Jul 2018 15:13:31 UTC +00:00>]
[32] pry(main)> ingredient
=> #<Ingredient:0x00007f8d4e829780
 id: 2,
 name: "flour",
 unit: "cup",
 created_at: Wed, 18 Jul 2018 15:13:31 UTC +00:00,
 updated_at: Wed, 18 Jul 2018 15:13:31 UTC +00:00>
[33] pry(main)> ingredient.recipes
NoMethodError: undefined method `recipes' for #<Ingredient:0x00007f8d4e829780>
from /Users/dkirschner/.rvm/gems/ruby-2.5.0/gems/activemodel-5.1.4/lib/active_model/attribute_methods.rb:432:in `method_missing'
[34] pry(main)> ingredient.cook
NoMethodError: undefined method `cook' for #<Ingredient:0x00007f8d4e829780>
from /Users/dkirschner/.rvm/gems/ruby-2.5.0/gems/activemodel-5.1.4/lib/active_model/attribute_methods.rb:432:in `method_missing'
[35] pry(main)> reload!
Reloading...
=> true
[36] pry(main)> ingredient = Ingredient.last
  Ingredient Load (0.6ms)  SELECT  "ingredients".* FROM "ingredients" ORDER BY "ingredients"."id" DESC LIMIT $1  [["LIMIT", 1]]
=> #<Ingredient:0x00007f8d4af3be00
 id: 2,
 name: "flour",
 unit: "cup",
 created_at: Wed, 18 Jul 2018 15:13:31 UTC +00:00,
 updated_at: Wed, 18 Jul 2018 15:13:31 UTC +00:00>
[37] pry(main)> ingredient.recipes
  Recipe Load (0.6ms)  SELECT "recipes".* FROM "recipes" INNER JOIN "meals" ON "recipes"."id" = "meals"."recipe_id" WHERE "meals"."ingredient_id" = $1  [["ingredient_id", 2]]
=> [#<Recipe:0x00007f8d4acef7a0
  id: 1,
  name: "Waffles",
  description: "Breakfast food",
  created_at: Wed, 18 Jul 2018 15:11:32 UTC +00:00,
  updated_at: Wed, 18 Jul 2018 15:11:32 UTC +00:00>]
# using an instance method `cook` defined in the Ingredient class (ingredient.rb)
[38] pry(main)> ingredient.cook
cooking
=> nil
[39] pry(main)> recipe = Recipe.last
  Recipe Load (0.4ms)  SELECT  "recipes".* FROM "recipes" ORDER BY "recipes"."id" DESC LIMIT $1  [["LIMIT", 1]]
=> #<Recipe:0x00007f8d4ea6d9b0
 id: 1,
 name: "Waffles",
 description: "Breakfast food",
 created_at: Wed, 18 Jul 2018 15:11:32 UTC +00:00,
 updated_at: Wed, 18 Jul 2018 15:11:32 UTC +00:00>