Created
April 16, 2015 14:16
-
-
Save k00ka/2cb1128f90659676fce3 to your computer and use it in GitHub Desktop.
W4D2 Lighthouse PT Toronto - ActiveRecord Associations
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Movie < ActiveRecord::Base | |
has_many :reviews | |
has_many :users, through: :reviews | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# create an in-memory Movie instance (and throw it away, oops) | |
2.1.3 :001 > Movie.new | |
=> #<Movie id: nil, created_at: nil, updated_at: nil> | |
# create a persisted Movie object (also capture it in the local variable m) | |
2.1.3 :002 > m=Movie.create | |
(0.2ms) begin transaction | |
SQL (4.7ms) INSERT INTO "movies" ("created_at", "updated_at") VALUES (?, ?) [["created_at", "2015-04-16 01:09:35.617271"], ["updated_at", "2015-04-16 01:09:35.617271"]] | |
(3.2ms) commit transaction | |
=> #<Movie id: 1, created_at: "2015-04-16 01:09:35", updated_at: "2015-04-16 01:09:35"> | |
# create a persisted User object (capture it in local variable u) | |
2.1.3 :003 > u=User.create | |
(0.0ms) begin transaction | |
SQL (2.9ms) INSERT INTO "users" ("created_at", "updated_at") VALUES (?, ?) [["created_at", "2015-04-16 01:10:33.593170"], ["updated_at", "2015-04-16 01:10:33.593170"]] | |
(2.5ms) commit transaction | |
=> #<User id: 1, created_at: "2015-04-16 01:10:33", updated_at: "2015-04-16 01:10:33"> | |
# create a persisted review but fail to capture it (note the id in the output to use in the next step) | |
2.1.3 :004 > Review.create | |
(0.1ms) begin transaction | |
SQL (4.5ms) INSERT INTO "reviews" ("created_at", "updated_at") VALUES (?, ?) [["created_at", "2015-04-16 01:10:46.450161"], ["updated_at", "2015-04-16 01:10:46.450161"]] | |
(3.5ms) commit transaction | |
=> #<Review id: 1, created_at: "2015-04-16 01:10:46", updated_at: "2015-04-16 01:10:46", user_id: nil, movie_id: nil> | |
# retrieve the persisted Review object from the database | |
2.1.3 :005 > r=Review.find(1) | |
Review Load (1.5ms) SELECT "reviews".* FROM "reviews" WHERE "reviews"."id" = ? LIMIT 1 [["id", 1]] | |
=> #<Review id: 1, created_at: "2015-04-16 01:10:46", updated_at: "2015-04-16 01:10:46", user_id: nil, movie_id: nil> | |
# ** USING THE AUTO-GENERATED (by ActiveRecord) ASSOCIATION ACCESSOR METHODS TO MODIFY ASSOCIATIONS ** | |
# set the review's user to the instance in the variable u | |
2.1.3 :006 > r.user = u | |
=> #<User id: 1, created_at: "2015-04-16 01:10:33", updated_at: "2015-04-16 01:10:33"> | |
# set the reviews's movie to the instance in the variable m | |
2.1.3 :007 > r.movie = m | |
=> #<Movie id: 1, created_at: "2015-04-16 01:09:35", updated_at: "2015-04-16 01:09:35"> | |
# a complete Review! But it's not saved yet. | |
2.1.3 :008 > r | |
=> #<Review id: 1, created_at: "2015-04-16 01:10:46", updated_at: "2015-04-16 01:10:46", user_id: 1, movie_id: 1> | |
2.1.3 :009 > r.save | |
(0.4ms) begin transaction | |
SQL (3.5ms) UPDATE "reviews" SET "movie_id" = ?, "updated_at" = ?, "user_id" = ? WHERE "reviews"."id" = 1 [["movie_id", 1], ["updated_at", "2015-04-16 01:11:44.023846"], ["user_id", 1]] | |
(3.0ms) commit transaction | |
=> true | |
# here's our movie | |
2.1.3 :010 > m | |
=> #<Movie id: 1, created_at: "2015-04-16 01:09:35", updated_at: "2015-04-16 01:09:35"> | |
# traverse the association to find it's review... | |
2.1.3 :011 > m.review | |
NoMethodError: undefined method `review' for #<Movie:0xc0d413c> | |
# acutally, it's reviews (one-to-many) | |
2.1.3 :012 > m.reviews | |
Review Load (0.9ms) SELECT "reviews".* FROM "reviews" WHERE "reviews"."movie_id" = ? [["movie_id", 1]] | |
=> #<ActiveRecord::Associations::CollectionProxy [#<Review id: 1, created_at: "2015-04-16 01:10:46", updated_at: "2015-04-16 01:11:44", user_id: 1, movie_id: 1>]> | |
# now traverse the has_many through relationship... | |
2.1.3 :013 > m.users | |
User Load (0.9ms) SELECT "users".* FROM "users" INNER JOIN "reviews" ON "users"."id" = "reviews"."user_id" WHERE "reviews"."movie_id" = ? [["movie_id", 1]] | |
=> #<ActiveRecord::Associations::CollectionProxy [#<User id: 1, created_at: "2015-04-16 01:10:33", updated_at: "2015-04-16 01:10:33">]> | |
# similarly traverse the associations from the User side... | |
2.1.3 :014 > u.reviews | |
Review Load (1.5ms) SELECT "reviews".* FROM "reviews" WHERE "reviews"."user_id" = ? [["user_id", 1]] | |
=> #<ActiveRecord::Associations::CollectionProxy [#<Review id: 1, created_at: "2015-04-16 01:10:46", updated_at: "2015-04-16 01:11:44", user_id: 1, movie_id: 1>]> | |
2.1.3 :015 > u.movies | |
Movie Load (1.6ms) SELECT "movies".* FROM "movies" INNER JOIN "reviews" ON "movies"."id" = "reviews"."movie_id" WHERE "reviews"."user_id" = ? [["user_id", 1]] | |
=> #<ActiveRecord::Associations::CollectionProxy [#<Movie id: 1, created_at: "2015-04-16 01:09:35", updated_at: "2015-04-16 01:09:35">]> | |
# answer the question: how many movies has this user reviewed? | |
# this is the "hard" way since it uses the more complicated has_many through association | |
2.1.3 :016 > u.movies.count | |
(1.6ms) SELECT COUNT(*) FROM "movies" INNER JOIN "reviews" ON "movies"."id" = "reviews"."movie_id" WHERE "reviews"."user_id" = ? [["user_id", 1]] | |
=> 1 | |
# using the knowledge that a User can only review each Movie once, this will always return the same result with less work | |
2.1.3 :017 > u.reviews.count | |
(1.3ms) SELECT COUNT(*) FROM "reviews" WHERE "reviews"."user_id" = ? [["user_id", 1]] | |
=> 1 | |
# from the review, we can now get to the movie without hitting the database! | |
2.1.3 :021 > r.movie | |
=> #<Movie id: 1, created_at: "2015-04-16 01:09:35", updated_at: "2015-04-16 01:09:35"> | |
# create some new objects... a new User and Movie | |
2.1.3 :022 > u2=User.create | |
(0.1ms) begin transaction | |
SQL (3.2ms) INSERT INTO "users" ("created_at", "updated_at") VALUES (?, ?) [["created_at", "2015-04-16 01:14:40.519086"], ["updated_at", "2015-04-16 01:14:40.519086"]] | |
(2.2ms) commit transaction | |
=> #<User id: 2, created_at: "2015-04-16 01:14:40", updated_at: "2015-04-16 01:14:40"> | |
2.1.3 :023 > m2=Movie.create | |
(0.1ms) begin transaction | |
SQL (4.2ms) INSERT INTO "movies" ("created_at", "updated_at") VALUES (?, ?) [["created_at", "2015-04-16 01:14:48.565140"], ["updated_at", "2015-04-16 01:14:48.565140"]] | |
(2.8ms) commit transaction | |
=> #<Movie id: 2, created_at: "2015-04-16 01:14:48", updated_at: "2015-04-16 01:14:48"> | |
# create a review for the second user, but for the first movie | |
2.1.3 :024 > r2=Review.create(user: u2, movie: m) | |
(0.1ms) begin transaction | |
SQL (3.4ms) INSERT INTO "reviews" ("created_at", "movie_id", "updated_at", "user_id") VALUES (?, ?, ?, ?) [["created_at", "2015-04-16 01:15:17.359864"], ["movie_id", 1], ["updated_at", "2015-04-16 01:15:17.359864"], ["user_id", 2]] | |
(3.6ms) commit transaction | |
=> #<Review id: 2, created_at: "2015-04-16 01:15:17", updated_at: "2015-04-16 01:15:17", user_id: 2, movie_id: 1> | |
# answer the question: how many reviews are there for the first Movie (the one stored in m) | |
2.1.3 :027 > m.reviews.count | |
(1.9ms) SELECT COUNT(*) FROM "reviews" WHERE "reviews"."movie_id" = ? [["movie_id", 1]] | |
=> 2 | |
# answer the question: which users have reviewed the first Movie (the one stored in m) | |
2.1.3 :028 > m.users | |
=> #<ActiveRecord::Associations::CollectionProxy [#<User id: 1, created_at: "2015-04-16 01:10:33", updated_at: "2015-04-16 01:10:33">]> | |
# answer the question: how many users have reviewed the first Movie (note: same as number of reviews) | |
2.1.3 :029 > m.users.count | |
(2.1ms) SELECT COUNT(*) FROM "users" INNER JOIN "reviews" ON "users"."id" = "reviews"."user_id" WHERE "reviews"."movie_id" = ? [["movie_id", 1]] | |
=> 2 | |
# answer the question: which users have reviewed the second Movie (the one stored in the variable m2) | |
2.1.3 :036 > m2.users | |
User Load (1.3ms) SELECT "users".* FROM "users" INNER JOIN "reviews" ON "users"."id" = "reviews"."user_id" WHERE "reviews"."movie_id" = ? [["movie_id", 2]] | |
=> #<ActiveRecord::Associations::CollectionProxy []> | |
# answer the question: how many users have reviewed the second movie (same as the number of reviews, just harder to compute) | |
2.1.3 :037 > m2.users.count | |
(2.5ms) SELECT COUNT(*) FROM "users" INNER JOIN "reviews" ON "users"."id" = "reviews"."user_id" WHERE "reviews"."movie_id" = ? [["movie_id", 2]] | |
=> 0 | |
# retrieve the reviews for the second Movie (there are none!) | |
2.1.3 :038 > m2.reviews | |
Review Load (1.8ms) SELECT "reviews".* FROM "reviews" WHERE "reviews"."movie_id" = ? [["movie_id", 2]] | |
=> #<ActiveRecord::Associations::CollectionProxy []> | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Review < ActiveRecord::Base | |
belongs_to :movie | |
belongs_to :user | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class User < ActiveRecord::Base | |
has_many :reviews | |
has_many :movies, through: :reviews | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment