foreign keys & rails...
TRANSCRIPT
Foreign Keys & Rails Associations
Arthur V. Klepchukov02.13/2oo8
let’s start a start-up!
myfacespace
Lets add ProfilePicsBETA
users:
•id
•name
•...
•etc.
We need... users!
Iteration 1:: naiveusers:
•id•name•email•...•profile_picture_path
Iteration 2 ::1-1 relationship
users: (has_one :profile_pic)
•...
profile_pics: (belongs_to :user)•id•user_id # foreign key to user!•picture_path•hot_or_not
Iteration 2 ::1-1 relationship
class ProfilePic < ActiveRecord::Basebelongs_to :user
end
1 pic is boring!Let’s add PhotoAlbumsBETA
profile pics
id
user_id
...
users
id
name
...
class User < ActiveRecord::Basehas_one :profile_pic
end
Iteration 1 :: naive
users:
•...•album_title•album_public•album_being_watched_by_CIA
UGLY!only ONE photo album
per user!!!
Iteration 2 ::1-M relationship
users: (has_many :albums)
•...
albums: (belongs_to :user)•id•user_id # foreign key to user!•title•public•being_watched_by_CIA
Iteration 2 ::1-M relationship
class Album < ActiveRecord::Basebelongs_to :user
end
albums
id
user_id
...
users
id
name
...
class User < ActiveRecord::Basehas_many :albums
end
Let’s add groupsBETA
Iteration 1 :: naiveusers:
•...•group1_name•group1_revolutionary_mission_statement
•...•groupN_name•groupN_revolutionary_mission_statement
Right... ?
NO!!!very ugly!
Iteration 2 ::M-M relationship
users: (has_and_belongs_to_many :groups)
• ...
groups: (has_and_belongs_to_many :users)
• id
• name
• revolutionary_mission_statement
groups_users: <<< join table, name matters (in Rails)
• group_id # foreign key to group!
• user_id # foreign key to user!
Iteration 2 ::M-M relationship
class Group < ActiveRecord::Basehas_and_belongs_to_many :users
end
groups
idmission_statement
...
users
id
name
...
class User < ActiveRecord::Basehas_and_belongs_to_many :groups
end
groups_usersgroup_iduser_id
Notice: no corresponding model!
Why bother?
•Logical Organization
•Avoid functional dependencies
•Easier to write queries in general
•Rails got your back- helps you avoid some join queries!
Simple Join QuerySELECT u.name, p.hot_or_not FROM users u INNER JOIN profile_pics p ON u.id = p.user_id;
Give me the name and hot_or_not status of each user with a profile picture.
Ugly Join QuerySELECT * FROM users u INNER JOIN groups_users gu ON u.id = gu.user_id INNER JOIN groups g ON gu.group_id = g.id LEFT OUTER JOIN profile_pictures p ON u.id = p.user_id WHERE g.name LIKE “%Ron Obama%” AND p.picture_path == NULL;
:(
Rails got my back?@user = User.find(:first)@groups = @user.groups # all of the groups this user belongs to
@user.profile_pic.hot_or_not = "NOT!" # makes this user ugly as far as the internet is concerned
@user.albums.each { |album| raise HorribleException if album.name =~ /NSFW/ } # your boss is looking...
Important details
•@user.save # DON’T FORGET! required for the changes on the previous slide to actually take effect (more on this later)
•@users = User.find( :all, :include => [:albums, :groups] ) # vital optimization if dealing with users and their albums and their groups
Remember
•Foreign keys are important in keeping a sane DB
•Rails makes working with typical relationships easy
•Much, much more to learn:- Agile Web Dev :: Ch. 18- CS 186
Special ThanksSQL & Prof. Joe Hellerstein
Next step: VC funding