SlideShare a Scribd company logo
Associations
Modeling database relationships
with ActiveRecord
Database Modeling
The “relational” in relational database
Database Types
Database Types

Rails was designed with a relational database bias
Database Types

Rails was designed with a relational database bias
  Though it can work with other tools, we will stick with
  this primary focus
Database Types

Rails was designed with a relational database bias
  Though it can work with other tools, we will stick with
  this primary focus
ActiveRecord can work with the SQL these databases
use to make queries
Database Types

Rails was designed with a relational database bias
  Though it can work with other tools, we will stick with
  this primary focus
ActiveRecord can work with the SQL these databases
use to make queries
One of the ways it does that is to manage the
relationships of data in separate tables
Relationship Types
Relationship Types

There are only three types of relationships in SQL
Relationship Types

There are only three types of relationships in SQL
  One to one
Relationship Types

There are only three types of relationships in SQL
  One to one
  One to many
Relationship Types

There are only three types of relationships in SQL
  One to one
  One to many
  Many to many
Relationship Types

There are only three types of relationships in SQL
  One to one
  One to many
  Many to many
    This doesn’t really exist, but it can be simulated
One to One
        users
id first_name last_name
1   James        Gray
2   Dana         Gray


                                  photos
                id      user_id             path
                1         1           /images/james.png
One to One
        users
id first_name last_name
1   James        Gray
2   Dana         Gray


                                  photos
                id      user_id             path
                1         1           /images/james.png
One to Many
              articles
id    title              body        comments
1 The CRUD                …     id article_id    body
2 Associations            …     1      1         First!
                                2      1         Tard.
                                3      1        Am not!
                                4      2        Viagra
                                5      2        Spam!
One to Many
              articles
id    title              body        comments
1 The CRUD                …     id article_id    body
2 Associations            …     1      1         First!
                                2      1         Tard.
                                3      1        Am not!
                                4      2        Viagra
                                5      2        Spam!
One to Many
              articles
id    title              body        comments
1 The CRUD                …     id article_id    body
2 Associations            …     1      1         First!
                                2      1         Tard.
                                3      1        Am not!
                                4      2        Viagra
                                5      2        Spam!
photos
Many to Many         id          path
                     1 /images/mac.jpg

     taggings        2 /images/pc.bmp

id photo_id tag_id
1    1          1               tags
                          id    name
2    1          2
                          1 computer
3    1          3
                          2      sexy
4    2          4
                          3     lickable
                          4      junk
photos
Many to Many         id          path
                     1 /images/mac.jpg

     taggings        2 /images/pc.bmp

id photo_id tag_id
1    1          1               tags
                          id    name
2    1          2
                          1 computer
3    1          3
                          2      sexy
4    2          4
                          3     lickable
                          4      junk
photos
Many to Many         id          path
                     1 /images/mac.jpg

     taggings        2 /images/pc.bmp

id photo_id tag_id
1    1          1               tags
                          id    name
2    1          2
                          1 computer
3    1          3
                          2      sexy
4    2          4
                          3     lickable
                          4      junk
Many to Many (Two Tables)
       followings                    users
id follower_id followed_id   id first_name last_name
1      1            4        1   James       Gray
2      2            4        2   Dana        Gray
3      3            1        3   Super       Man
4      4            1        4    Bat        Man
5      5            1        5   Spider      Man
Many to Many (Two Tables)
       followings                    users
id follower_id followed_id   id first_name last_name
1      1            4        1   James       Gray
2      2            4        2   Dana        Gray
3      3            1        3   Super       Man
4      4            1        4    Bat        Man
5      5            1        5   Spider      Man
Many to Many (Two Tables)
       followings                    users
id follower_id followed_id   id first_name last_name
1      1            4        1   James       Gray
2      2            4        2   Dana        Gray
3      3            1        3   Super       Man
4      4            1        4    Bat        Man
5      5            1        5   Spider      Man
Conventions at Work
                         articles
                   id   title   body
                   1 Unique         …


                        comments
              id article_id         body
               1        1           First!
Conventions at Work
Rails favors conventions             articles
                               id   title   body
                               1 Unique         …


                                    comments
                           id article_id        body
                           1        1           First!
Conventions at Work
Rails favors conventions             articles
With associations:             id   title   body
                               1 Unique         …


                                    comments
                           id article_id        body
                           1        1           First!
Conventions at Work
Rails favors conventions             articles
With associations:             id   title   body
  Auto-incremented ID          1 Unique         …
  fields

                                    comments
                           id article_id        body
                           1        1           First!
Conventions at Work
Rails favors conventions             articles
With associations:             id   title   body
  Auto-incremented ID          1 Unique         …
  fields
  Table name is plural
                                    comments
  for the collection
                           id article_id        body
                           1        1           First!
Conventions at Work
Rails favors conventions             articles
With associations:             id   title   body
  Auto-incremented ID          1 Unique         …
  fields
  Table name is plural
                                    comments
  for the collection
                           id article_id        body
  Foreign key is a
  singular item plus _id   1        1           First!
Associations, Rails Style
Let’s turn those examples into real Rails code
Rails Macros
Rails Macros
Use belongs_to() on the ID side of a one to one or one
to many
Rails Macros
Use belongs_to() on the ID side of a one to one or one
to many
Use has_one() on the other side of a one to one
Rails Macros
Use belongs_to() on the ID side of a one to one or one
to many
Use has_one() on the other side of a one to one
Use has_many() on the other side of a one to many
Rails Macros
Use belongs_to() on the ID side of a one to one or one
to many
Use has_one() on the other side of a one to one
Use has_many() on the other side of a one to many
Use two belongs_to() calls for the join model of a
many to many
Rails Macros
Use belongs_to() on the ID side of a one to one or one
to many
Use has_one() on the other side of a one to one
Use has_many() on the other side of a one to many
Use two belongs_to() calls for the join model of a
many to many
Use has_many() and has_many(…, :through => …)
for the data models of a many to many
One to Many
              articles
id    title              body        comments
1 The CRUD                …     id article_id    body
2 Associations            …     1      1         First!
                                2      1         Tard.
                                3      1        Am not!
                                4      2        Viagra
                                5      2        Spam!
One to Many
An article has_many() comments
class Article < ActiveRecord::Base
    has_many :comments
   end




                                        class Comment < ActiveRecord::Base
                                         belongs_to :article
                                        end




One to Many
An article has_many() comments
Associated Models
You can query through the association
>> crud = Article.first
   => #<Article id: 1, title: "The CRUD", body: "...", …>
   >> crud.comments.count
   => 3
   >> crud.comments
   => [#<Comment id: 1, article_id: 1, body: "First!", …>,
     #<Comment id: 2, article_id: 1, body: "Tard.", …>,
     #<Comment id: 3, article_id: 1, body: "Am not!", …>]

   >>   crud.comments.last
   =>   #<Comment id: 3, article_id: 1, body: "Am not!", …>
   >>   crud.comments.last.article
   =>   #<Article id: 1, title: "The CRUD", body: "...", …>




Associated Models
You can query through the association
>> crud = Article.first
   => #<Article id: 1, title: "The CRUD", body: "...", …>
   >> crud.comments.count
   => 3
   >> crud.comments
   => [#<Comment id: 1, article_id: 1, body: "First!", …>,
     #<Comment id: 2, article_id: 1, body: "Tard.", …>,
     #<Comment id: 3, article_id: 1, body: "Am not!", …>]

   >>   crud.comments.last
   =>   #<Comment id: 3, article_id: 1, body: "Am not!", …>
   >>   crud.comments.last.article
   =>   #<Article id: 1, title: "The CRUD", body: "...", …>




Associated Models
You can query through the association
>> crud = Article.first
   => #<Article id: 1, title: "The CRUD", body: "...", …>
   >> crud.comments.count
   => 3
   >> crud.comments
   => [#<Comment id: 1, article_id: 1, body: "First!", …>,
     #<Comment id: 2, article_id: 1, body: "Tard.", …>,
     #<Comment id: 3, article_id: 1, body: "Am not!", …>]

   >>   crud.comments.last
   =>   #<Comment id: 3, article_id: 1, body: "Am not!", …>
   >>   crud.comments.last.article
   =>   #<Article id: 1, title: "The CRUD", body: "...", …>




Associated Models
You can query through the association
>> crud = Article.first
   => #<Article id: 1, title: "The CRUD", body: "...", …>
   >> crud.comments.count
   => 3
   >> crud.comments
   => [#<Comment id: 1, article_id: 1, body: "First!", …>,
     #<Comment id: 2, article_id: 1, body: "Tard.", …>,
     #<Comment id: 3, article_id: 1, body: "Am not!", …>]

   >>   crud.comments.last
   =>   #<Comment id: 3, article_id: 1, body: "Am not!", …>
   >>   crud.comments.last.article
   =>   #<Article id: 1, title: "The CRUD", body: "...", …>




Associated Models
You can query through the association
>> crud = Article.first
   => #<Article id: 1, title: "The CRUD", body: "...", …>
   >> crud.comments.count
   => 3
   >> crud.comments
   => [#<Comment id: 1, article_id: 1, body: "First!", …>,
     #<Comment id: 2, article_id: 1, body: "Tard.", …>,
     #<Comment id: 3, article_id: 1, body: "Am not!", …>]

   >>   crud.comments.last
   =>   #<Comment id: 3, article_id: 1, body: "Am not!", …>
   >>   crud.comments.last.article
   =>   #<Article id: 1, title: "The CRUD", body: "...", …>




Associated Models
You can query through the association
Adding to an Association
There are multiple ways to add in new models
>>   a = Article.create!(:title => "Needs Comments")
      =>   #<Article id: 3, title: "Needs Comments", body: nil, …>
      >>   a.comments
      =>   []

      >> a.comments.create!(:body => "create!()")
      => #<Comment id: 6, article_id: 3, body: "create!()", …>
      >> a.comments << Comment.new(:body => "<<")
      => [#<Comment id: 6, article_id: 3, body: "create!()", …>,
        #<Comment id: 7, article_id: 3, body: "<<", …>]
      >> c = a.comments.build(:body => "build()")
      => #<Comment id: nil, article_id: 3, body: "build()",
              created_at: nil, updated_at: nil>
      >> c.save!
      => true

      >> a.comments
      => [#<Comment id: 6, article_id: 3, body: "create!()", …>,
        #<Comment id: 7, article_id: 3, body: "<<", …>,
        #<Comment id: 8, article_id: 3, body: "build()", …>]




Adding to an Association
There are multiple ways to add in new models
>>   a = Article.create!(:title => "Needs Comments")
      =>   #<Article id: 3, title: "Needs Comments", body: nil, …>
      >>   a.comments
      =>   []

      >> a.comments.create!(:body => "create!()")
      => #<Comment id: 6, article_id: 3, body: "create!()", …>
      >> a.comments << Comment.new(:body => "<<")
      => [#<Comment id: 6, article_id: 3, body: "create!()", …>,
        #<Comment id: 7, article_id: 3, body: "<<", …>]
      >> c = a.comments.build(:body => "build()")
      => #<Comment id: nil, article_id: 3, body: "build()",
              created_at: nil, updated_at: nil>
      >> c.save!
      => true

      >> a.comments
      => [#<Comment id: 6, article_id: 3, body: "create!()", …>,
        #<Comment id: 7, article_id: 3, body: "<<", …>,
        #<Comment id: 8, article_id: 3, body: "build()", …>]




Adding to an Association
There are multiple ways to add in new models
>>   a = Article.create!(:title => "Needs Comments")
      =>   #<Article id: 3, title: "Needs Comments", body: nil, …>
      >>   a.comments
      =>   []

      >> a.comments.create!(:body => "create!()")
      => #<Comment id: 6, article_id: 3, body: "create!()", …>
      >> a.comments << Comment.new(:body => "<<")
      => [#<Comment id: 6, article_id: 3, body: "create!()", …>,
        #<Comment id: 7, article_id: 3, body: "<<", …>]
      >> c = a.comments.build(:body => "build()")
      => #<Comment id: nil, article_id: 3, body: "build()",
              created_at: nil, updated_at: nil>
      >> c.save!
      => true

      >> a.comments
      => [#<Comment id: 6, article_id: 3, body: "create!()", …>,
        #<Comment id: 7, article_id: 3, body: "<<", …>,
        #<Comment id: 8, article_id: 3, body: "build()", …>]




Adding to an Association
There are multiple ways to add in new models
>>   a = Article.create!(:title => "Needs Comments")
      =>   #<Article id: 3, title: "Needs Comments", body: nil, …>
      >>   a.comments
      =>   []

      >> a.comments.create!(:body => "create!()")
      => #<Comment id: 6, article_id: 3, body: "create!()", …>
      >> a.comments << Comment.new(:body => "<<")
      => [#<Comment id: 6, article_id: 3, body: "create!()", …>,
        #<Comment id: 7, article_id: 3, body: "<<", …>]
      >> c = a.comments.build(:body => "build()")
      => #<Comment id: nil, article_id: 3, body: "build()",
              created_at: nil, updated_at: nil>
      >> c.save!
      => true

      >> a.comments
      => [#<Comment id: 6, article_id: 3, body: "create!()", …>,
        #<Comment id: 7, article_id: 3, body: "<<", …>,
        #<Comment id: 8, article_id: 3, body: "build()", …>]




Adding to an Association
There are multiple ways to add in new models
Deleting Associated Models
To delete associated models, find normally
and call destroy()
>> a.comments
   => [#<Comment id: 6, article_id: 3, body: "create!()", …>,
     #<Comment id: 7, article_id: 3, body: "<<", …>,
     #<Comment id: 8, article_id: 3, body: "build()", …>]
   >> c = a.comments.find(8)
   => #<Comment id: 8, article_id: 3, body: "build()", …>
   >> c.destroy if c
   => #<Comment id: 8, article_id: 3, body: "build()", …>
   >> a.comments(true)
   => [#<Comment id: 6, article_id: 3, body: "create!()", …>,
     #<Comment id: 7, article_id: 3, body: "<<", …>]




Deleting Associated Models
To delete associated models, find normally
and call destroy()
>> a.comments
   => [#<Comment id: 6, article_id: 3, body: "create!()", …>,
     #<Comment id: 7, article_id: 3, body: "<<", …>,
     #<Comment id: 8, article_id: 3, body: "build()", …>]
   >> c = a.comments.find(8)
   => #<Comment id: 8, article_id: 3, body: "build()", …>
   >> c.destroy if c
   => #<Comment id: 8, article_id: 3, body: "build()", …>
   >> a.comments(true)
   => [#<Comment id: 6, article_id: 3, body: "create!()", …>,
     #<Comment id: 7, article_id: 3, body: "<<", …>]




Deleting Associated Models
To delete associated models, find normally
and call destroy()
>> a.comments
   => [#<Comment id: 6, article_id: 3, body: "create!()", …>,
     #<Comment id: 7, article_id: 3, body: "<<", …>,
     #<Comment id: 8, article_id: 3, body: "build()", …>]
   >> c = a.comments.find(8)
   => #<Comment id: 8, article_id: 3, body: "build()", …>
   >> c.destroy if c
   => #<Comment id: 8, article_id: 3, body: "build()", …>
   >> a.comments(true)
   => [#<Comment id: 6, article_id: 3, body: "create!()", …>,
     #<Comment id: 7, article_id: 3, body: "<<", …>]




Deleting Associated Models
To delete associated models, find normally
and call destroy()
>> a.comments
   => [#<Comment id: 6, article_id: 3, body: "create!()", …>,
     #<Comment id: 7, article_id: 3, body: "<<", …>,
     #<Comment id: 8, article_id: 3, body: "build()", …>]
   >> c = a.comments.find(8)
   => #<Comment id: 8, article_id: 3, body: "build()", …>
   >> c.destroy if c
   => #<Comment id: 8, article_id: 3, body: "build()", …>
   >> a.comments(true)
   => [#<Comment id: 6, article_id: 3, body: "create!()", …>,
     #<Comment id: 7, article_id: 3, body: "<<", …>]




Deleting Associated Models
To delete associated models, find normally
and call destroy()
Using Associations Correctly
Using Associations Correctly

 You should very rarely need to refer to an ID
Using Associations Correctly

 You should very rarely need to refer to an ID
   Let Rails worry about that for you
Using Associations Correctly

 You should very rarely need to refer to an ID
   Let Rails worry about that for you
 It’s safer to scope as many queries as possible through
 the association
Using Associations Correctly

 You should very rarely need to refer to an ID
   Let Rails worry about that for you
 It’s safer to scope as many queries as possible through
 the association
   There’s less chance to affect the wrong data
Using Associations Correctly

 You should very rarely need to refer to an ID
   Let Rails worry about that for you
 It’s safer to scope as many queries as possible through
 the association
   There’s less chance to affect the wrong data
   It adds security against users trying to spoof ID’s
One to One
        users
id first_name last_name
1   James        Gray
2   Dana         Gray


                                  photos
                id      user_id             path
                1         1           /images/james.png
One to One
A user has_one() photo
class User < ActiveRecord::Base
    has_one :photo
   end




                                     class Photo < ActiveRecord::Base
                                      belongs_to :user
                                     end




One to One
A user has_one() photo
Model Attributes
Just assign a belongs_to()/has_one() to set it
(or call build_photo()/create_photo())
>>   james = User.find_by_first_name("James")
 =>   #<User id: 1, first_name: "James", last_name: "Gray", …>
 >>   james.photo = Photo.new(:path => "/images/james.png")
 =>   #<Photo id: 1, user_id: 1, path: "/images/james.png", …>




Model Attributes
Just assign a belongs_to()/has_one() to set it
(or call build_photo()/create_photo())
>>   james = User.find_by_first_name("James")
 =>   #<User id: 1, first_name: "James", last_name: "Gray", …>
 >>   james.photo = Photo.new(:path => "/images/james.png")
 =>   #<Photo id: 1, user_id: 1, path: "/images/james.png", …>




Model Attributes
Just assign a belongs_to()/has_one() to set it
(or call build_photo()/create_photo())
photos
Many to Many         id          path
                     1 /images/mac.jpg

     taggings        2 /images/pc.bmp

id photo_id tag_id
1    1          1               tags
                          id    name
2    1          2
                          1 computer
3    1          3
                          2      sexy
4    2          4
                          3     lickable
                          4      junk
Many to Many
Photos have many tags
class Photo < ActiveRecord::Base
                                       has_many :taggings
                                       has_many :tags, :through => :taggings
                                      end



 class Tagging < ActiveRecord::Base
  belongs_to :photo
  belongs_to :tag
 end



                                  class Tag < ActiveRecord::Base
                                   has_many :taggings
                                   has_many :photos, :through => :taggings
                                  end




Many to Many
Photos have many tags
class Photo < ActiveRecord::Base
                                       has_many :taggings
                                       has_many :tags, :through => :taggings
                                      end



 class Tagging < ActiveRecord::Base
  belongs_to :photo
  belongs_to :tag
 end



                                  class Tag < ActiveRecord::Base
                                   has_many :taggings
                                   has_many :photos, :through => :taggings
                                  end




Many to Many
Photos have many tags
has_many :through
The nested association is mostly managed by
Rails for you
>> mac = Photo.first
     => #<Photo id: 1, user_id: 1, path: "/images/mac.jpg", …>
     >> mac.taggings
     => [#<Tagging id: 1, photo_id: 1, tag_id: 1, …>,
       #<Tagging id: 2, photo_id: 1, tag_id: 2, …>,
       #<Tagging id: 3, photo_id: 1, tag_id: 3, …>]
     >> mac.tags
     => [#<Tag id: 1, name: "computer", …>,
       #<Tag id: 2, name: "sexy", …>,
       #<Tag id: 3, name: "lickable", …>]

     >>   pc = Photo.last
     =>   #<Photo id: 2, user_id: nil, path: "/images/pc.bmp", …>
     >>   comp = Tag.find_or_create_by_name("computer")
     =>   #<Tag id: 1, name: "computer", …>
     >>   pc.taggings.create!(:tag => comp)
     =>   #<Tagging id: 5, photo_id: 2, tag_id: 1, …>




has_many :through
The nested association is mostly managed by
Rails for you
>> mac = Photo.first
     => #<Photo id: 1, user_id: 1, path: "/images/mac.jpg", …>
     >> mac.taggings
     => [#<Tagging id: 1, photo_id: 1, tag_id: 1, …>,
       #<Tagging id: 2, photo_id: 1, tag_id: 2, …>,
       #<Tagging id: 3, photo_id: 1, tag_id: 3, …>]
     >> mac.tags
     => [#<Tag id: 1, name: "computer", …>,
       #<Tag id: 2, name: "sexy", …>,
       #<Tag id: 3, name: "lickable", …>]

     >>   pc = Photo.last
     =>   #<Photo id: 2, user_id: nil, path: "/images/pc.bmp", …>
     >>   comp = Tag.find_or_create_by_name("computer")
     =>   #<Tag id: 1, name: "computer", …>
     >>   pc.taggings.create!(:tag => comp)
     =>   #<Tagging id: 5, photo_id: 2, tag_id: 1, …>




has_many :through
The nested association is mostly managed by
Rails for you
>> mac = Photo.first
     => #<Photo id: 1, user_id: 1, path: "/images/mac.jpg", …>
     >> mac.taggings
     => [#<Tagging id: 1, photo_id: 1, tag_id: 1, …>,
       #<Tagging id: 2, photo_id: 1, tag_id: 2, …>,
       #<Tagging id: 3, photo_id: 1, tag_id: 3, …>]
     >> mac.tags
     => [#<Tag id: 1, name: "computer", …>,
       #<Tag id: 2, name: "sexy", …>,
       #<Tag id: 3, name: "lickable", …>]

     >>   pc = Photo.last
     =>   #<Photo id: 2, user_id: nil, path: "/images/pc.bmp", …>
     >>   comp = Tag.find_or_create_by_name("computer")
     =>   #<Tag id: 1, name: "computer", …>
     >>   pc.taggings.create!(:tag => comp)
     =>   #<Tagging id: 5, photo_id: 2, tag_id: 1, …>




has_many :through
The nested association is mostly managed by
Rails for you
>> mac = Photo.first
     => #<Photo id: 1, user_id: 1, path: "/images/mac.jpg", …>
     >> mac.taggings
     => [#<Tagging id: 1, photo_id: 1, tag_id: 1, …>,
       #<Tagging id: 2, photo_id: 1, tag_id: 2, …>,
       #<Tagging id: 3, photo_id: 1, tag_id: 3, …>]
     >> mac.tags
     => [#<Tag id: 1, name: "computer", …>,
       #<Tag id: 2, name: "sexy", …>,
       #<Tag id: 3, name: "lickable", …>]

     >>   pc = Photo.last
     =>   #<Photo id: 2, user_id: nil, path: "/images/pc.bmp", …>
     >>   comp = Tag.find_or_create_by_name("computer")
     =>   #<Tag id: 1, name: "computer", …>
     >>   pc.taggings.create!(:tag => comp)
     =>   #<Tagging id: 5, photo_id: 2, tag_id: 1, …>




has_many :through
The nested association is mostly managed by
Rails for you
Many to Many (Two Tables)
       followings                    users
id follower_id followed_id   id first_name last_name
1      1            4        1   James       Gray
2      2            4        2   Dana        Gray
3      3            1        3   Super       Man
4      4            1        4    Bat        Man
5      5            1        5   Spider      Man
Many to Many (Two Tables)
Users have many followers
class Following < ActiveRecord::Base
 belongs_to :follower, :class_name => "User",
                :foreign_key => :follower_id
 belongs_to :followed, :class_name => "User",
                :foreign_key => :followed_id
end



          class User < ActiveRecord::Base
           has_many :other_followings, :class_name => "Following",
                             :foreign_key => :followed_id
           has_many :followers,      :through     => :other_followings
           has_many :self_followings, :class_name => "Following",
                             :foreign_key => :follower_id
           has_many :followed_by,      :through    => :self_followings,
                             :source     => :followed
          end




Many to Many (Two Tables)
Users have many followers
class Following < ActiveRecord::Base
 belongs_to :follower, :class_name => "User",
                :foreign_key => :follower_id
 belongs_to :followed, :class_name => "User",
                :foreign_key => :followed_id
end



          class User < ActiveRecord::Base
           has_many :other_followings, :class_name => "Following",
                             :foreign_key => :followed_id
           has_many :followers,      :through     => :other_followings
           has_many :self_followings, :class_name => "Following",
                             :foreign_key => :follower_id
           has_many :followed_by,      :through    => :self_followings,
                             :source     => :followed
          end




Many to Many (Two Tables)
Users have many followers
class Following < ActiveRecord::Base
 belongs_to :follower, :class_name => "User",
                :foreign_key => :follower_id
 belongs_to :followed, :class_name => "User",
                :foreign_key => :followed_id
end



          class User < ActiveRecord::Base
           has_many :other_followings, :class_name => "Following",
                             :foreign_key => :followed_id
           has_many :followers,      :through     => :other_followings
           has_many :self_followings, :class_name => "Following",
                             :foreign_key => :follower_id
           has_many :followed_by,      :through    => :self_followings,
                             :source     => :followed
          end




Many to Many (Two Tables)
Users have many followers
class Following < ActiveRecord::Base
 belongs_to :follower, :class_name => "User",
                :foreign_key => :follower_id
 belongs_to :followed, :class_name => "User",
                :foreign_key => :followed_id
end



          class User < ActiveRecord::Base
           has_many :other_followings, :class_name => "Following",
                             :foreign_key => :followed_id
           has_many :followers,      :through     => :other_followings
           has_many :self_followings, :class_name => "Following",
                             :foreign_key => :follower_id
           has_many :followed_by,      :through    => :self_followings,
                             :source     => :followed
          end




Many to Many (Two Tables)
Users have many followers
Two-way Relationships
Once you get the relationships right, Rails can
still manage the messy details
>> james = User.find_by_first_name("James")
    => #<User id: 1, first_name: "James", last_name: "Gray", …>
    >> james.followers
    => [#<User id: 3, first_name: "Super", last_name: "Man", …>,
      #<User id: 4, first_name: "Bat", last_name: "Man", …>,
      #<User id: 5, first_name: "Spider", last_name: "Man", …>]
    >> james.followed_by
    => [#<User id: 4, first_name: "Bat", last_name: "Man", …>]

    >> bat = User.find_by_first_name("Bat")
    => #<User id: 4, first_name: "Bat", last_name: "Man", …>
    >> bat.followers
    => [#<User id: 1, first_name: "James", last_name: "Gray", …>,
      #<User id: 2, first_name: "Dana", last_name: "Gray", …>]




Two-way Relationships
Once you get the relationships right, Rails can
still manage the messy details
>> james = User.find_by_first_name("James")
    => #<User id: 1, first_name: "James", last_name: "Gray", …>
    >> james.followers
    => [#<User id: 3, first_name: "Super", last_name: "Man", …>,
      #<User id: 4, first_name: "Bat", last_name: "Man", …>,
      #<User id: 5, first_name: "Spider", last_name: "Man", …>]
    >> james.followed_by
    => [#<User id: 4, first_name: "Bat", last_name: "Man", …>]

    >> bat = User.find_by_first_name("Bat")
    => #<User id: 4, first_name: "Bat", last_name: "Man", …>
    >> bat.followers
    => [#<User id: 1, first_name: "James", last_name: "Gray", …>,
      #<User id: 2, first_name: "Dana", last_name: "Gray", …>]




Two-way Relationships
Once you get the relationships right, Rails can
still manage the messy details
>> james = User.find_by_first_name("James")
    => #<User id: 1, first_name: "James", last_name: "Gray", …>
    >> james.followers
    => [#<User id: 3, first_name: "Super", last_name: "Man", …>,
      #<User id: 4, first_name: "Bat", last_name: "Man", …>,
      #<User id: 5, first_name: "Spider", last_name: "Man", …>]
    >> james.followed_by
    => [#<User id: 4, first_name: "Bat", last_name: "Man", …>]

    >> bat = User.find_by_first_name("Bat")
    => #<User id: 4, first_name: "Bat", last_name: "Man", …>
    >> bat.followers
    => [#<User id: 1, first_name: "James", last_name: "Gray", …>,
      #<User id: 2, first_name: "Dana", last_name: "Gray", …>]




Two-way Relationships
Once you get the relationships right, Rails can
still manage the messy details
Extras
Rails associations have quite a few options
Finder Options
and Dependance
Finder Options
and Dependance
Set :conditions, :order, etc. on associations
Finder Options
and Dependance
Set :conditions, :order, etc. on associations
  Example: :order => “created_at DESC”
Finder Options
and Dependance
Set :conditions, :order, etc. on associations
  Example: :order => “created_at DESC”
Specify what happens to associations with destroy()
Finder Options
and Dependance
Set :conditions, :order, etc. on associations
  Example: :order => “created_at DESC”
Specify what happens to associations with destroy()
  :dependent => :destroy forwards destroy()
Finder Options
and Dependance
Set :conditions, :order, etc. on associations
  Example: :order => “created_at DESC”
Specify what happens to associations with destroy()
  :dependent => :destroy forwards destroy()
  :dependent => :nullify breaks the link
Polymorphic Associations
Polymorphic Associations

Rails has a special type of “Polymorphic Association”
Polymorphic Associations

Rails has a special type of “Polymorphic Association”
Models are linked with a type and an ID
Polymorphic Associations

Rails has a special type of “Polymorphic Association”
Models are linked with a type and an ID
This makes it possible to link one model to multiple
different kinds of other models
Polymorphic Associations

Rails has a special type of “Polymorphic Association”
Models are linked with a type and an ID
This makes it possible to link one model to multiple
different kinds of other models
  For example, you might use a Comment model to
  allows users to comment on multiple things
  (products and reviews for example)
Questions?
Fleshing out the
Data Layer Lab
Your book has instructions on how to add new
models and associate them with existing tables

More Related Content

More from James Gray (17)

KEY
A Dickens of A Keynote
James Gray
 
KEY
I Doubt That!
James Gray
 
KEY
Regular expressions
James Gray
 
KEY
Counting on God
James Gray
 
KEY
In the Back of Your Mind
James Gray
 
PDF
Unblocked
James Gray
 
KEY
Module Magic
James Gray
 
KEY
API Design
James Gray
 
KEY
Amazon's Simple Storage Service (S3)
James Gray
 
KEY
Git and GitHub
James Gray
 
KEY
Test Coverage in Rails
James Gray
 
KEY
Rails Routing And Rendering
James Gray
 
KEY
Sending Email with Rails
James Gray
 
KEY
DRYing Up Rails Views and Controllers
James Gray
 
KEY
Building a Rails Interface
James Gray
 
KEY
Ruby
James Gray
 
KEY
Wed Development on Rails
James Gray
 
A Dickens of A Keynote
James Gray
 
I Doubt That!
James Gray
 
Regular expressions
James Gray
 
Counting on God
James Gray
 
In the Back of Your Mind
James Gray
 
Unblocked
James Gray
 
Module Magic
James Gray
 
API Design
James Gray
 
Amazon's Simple Storage Service (S3)
James Gray
 
Git and GitHub
James Gray
 
Test Coverage in Rails
James Gray
 
Rails Routing And Rendering
James Gray
 
Sending Email with Rails
James Gray
 
DRYing Up Rails Views and Controllers
James Gray
 
Building a Rails Interface
James Gray
 
Wed Development on Rails
James Gray
 

Recently uploaded (20)

PPTX
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
PDF
Complete JavaScript Notes: From Basics to Advanced Concepts.pdf
haydendavispro
 
PDF
Reverse Engineering of Security Products: Developing an Advanced Microsoft De...
nwbxhhcyjv
 
PPTX
WooCommerce Workshop: Bring Your Laptop
Laura Hartwig
 
PPTX
OpenID AuthZEN - Analyst Briefing July 2025
David Brossard
 
PPTX
Webinar: Introduction to LF Energy EVerest
DanBrown980551
 
PDF
Newgen Beyond Frankenstein_Build vs Buy_Digital_version.pdf
darshakparmar
 
PDF
LLMs.txt: Easily Control How AI Crawls Your Site
Keploy
 
PDF
SWEBOK Guide and Software Services Engineering Education
Hironori Washizaki
 
PDF
The Builder’s Playbook - 2025 State of AI Report.pdf
jeroen339954
 
PDF
[Newgen] NewgenONE Marvin Brochure 1.pdf
darshakparmar
 
PDF
NewMind AI - Journal 100 Insights After The 100th Issue
NewMind AI
 
PDF
CIFDAQ Market Insights for July 7th 2025
CIFDAQ
 
PDF
Building Real-Time Digital Twins with IBM Maximo & ArcGIS Indoors
Safe Software
 
PDF
July Patch Tuesday
Ivanti
 
PDF
Blockchain Transactions Explained For Everyone
CIFDAQ
 
PDF
Achieving Consistent and Reliable AI Code Generation - Medusa AI
medusaaico
 
PDF
Agentic AI lifecycle for Enterprise Hyper-Automation
Debmalya Biswas
 
PPTX
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
PDF
Chris Elwell Woburn, MA - Passionate About IT Innovation
Chris Elwell Woburn, MA
 
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
Complete JavaScript Notes: From Basics to Advanced Concepts.pdf
haydendavispro
 
Reverse Engineering of Security Products: Developing an Advanced Microsoft De...
nwbxhhcyjv
 
WooCommerce Workshop: Bring Your Laptop
Laura Hartwig
 
OpenID AuthZEN - Analyst Briefing July 2025
David Brossard
 
Webinar: Introduction to LF Energy EVerest
DanBrown980551
 
Newgen Beyond Frankenstein_Build vs Buy_Digital_version.pdf
darshakparmar
 
LLMs.txt: Easily Control How AI Crawls Your Site
Keploy
 
SWEBOK Guide and Software Services Engineering Education
Hironori Washizaki
 
The Builder’s Playbook - 2025 State of AI Report.pdf
jeroen339954
 
[Newgen] NewgenONE Marvin Brochure 1.pdf
darshakparmar
 
NewMind AI - Journal 100 Insights After The 100th Issue
NewMind AI
 
CIFDAQ Market Insights for July 7th 2025
CIFDAQ
 
Building Real-Time Digital Twins with IBM Maximo & ArcGIS Indoors
Safe Software
 
July Patch Tuesday
Ivanti
 
Blockchain Transactions Explained For Everyone
CIFDAQ
 
Achieving Consistent and Reliable AI Code Generation - Medusa AI
medusaaico
 
Agentic AI lifecycle for Enterprise Hyper-Automation
Debmalya Biswas
 
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
Chris Elwell Woburn, MA - Passionate About IT Innovation
Chris Elwell Woburn, MA
 
Ad

Associations in Rails

  • 2. Database Modeling The “relational” in relational database
  • 4. Database Types Rails was designed with a relational database bias
  • 5. Database Types Rails was designed with a relational database bias Though it can work with other tools, we will stick with this primary focus
  • 6. Database Types Rails was designed with a relational database bias Though it can work with other tools, we will stick with this primary focus ActiveRecord can work with the SQL these databases use to make queries
  • 7. Database Types Rails was designed with a relational database bias Though it can work with other tools, we will stick with this primary focus ActiveRecord can work with the SQL these databases use to make queries One of the ways it does that is to manage the relationships of data in separate tables
  • 9. Relationship Types There are only three types of relationships in SQL
  • 10. Relationship Types There are only three types of relationships in SQL One to one
  • 11. Relationship Types There are only three types of relationships in SQL One to one One to many
  • 12. Relationship Types There are only three types of relationships in SQL One to one One to many Many to many
  • 13. Relationship Types There are only three types of relationships in SQL One to one One to many Many to many This doesn’t really exist, but it can be simulated
  • 14. One to One users id first_name last_name 1 James Gray 2 Dana Gray photos id user_id path 1 1 /images/james.png
  • 15. One to One users id first_name last_name 1 James Gray 2 Dana Gray photos id user_id path 1 1 /images/james.png
  • 16. One to Many articles id title body comments 1 The CRUD … id article_id body 2 Associations … 1 1 First! 2 1 Tard. 3 1 Am not! 4 2 Viagra 5 2 Spam!
  • 17. One to Many articles id title body comments 1 The CRUD … id article_id body 2 Associations … 1 1 First! 2 1 Tard. 3 1 Am not! 4 2 Viagra 5 2 Spam!
  • 18. One to Many articles id title body comments 1 The CRUD … id article_id body 2 Associations … 1 1 First! 2 1 Tard. 3 1 Am not! 4 2 Viagra 5 2 Spam!
  • 19. photos Many to Many id path 1 /images/mac.jpg taggings 2 /images/pc.bmp id photo_id tag_id 1 1 1 tags id name 2 1 2 1 computer 3 1 3 2 sexy 4 2 4 3 lickable 4 junk
  • 20. photos Many to Many id path 1 /images/mac.jpg taggings 2 /images/pc.bmp id photo_id tag_id 1 1 1 tags id name 2 1 2 1 computer 3 1 3 2 sexy 4 2 4 3 lickable 4 junk
  • 21. photos Many to Many id path 1 /images/mac.jpg taggings 2 /images/pc.bmp id photo_id tag_id 1 1 1 tags id name 2 1 2 1 computer 3 1 3 2 sexy 4 2 4 3 lickable 4 junk
  • 22. Many to Many (Two Tables) followings users id follower_id followed_id id first_name last_name 1 1 4 1 James Gray 2 2 4 2 Dana Gray 3 3 1 3 Super Man 4 4 1 4 Bat Man 5 5 1 5 Spider Man
  • 23. Many to Many (Two Tables) followings users id follower_id followed_id id first_name last_name 1 1 4 1 James Gray 2 2 4 2 Dana Gray 3 3 1 3 Super Man 4 4 1 4 Bat Man 5 5 1 5 Spider Man
  • 24. Many to Many (Two Tables) followings users id follower_id followed_id id first_name last_name 1 1 4 1 James Gray 2 2 4 2 Dana Gray 3 3 1 3 Super Man 4 4 1 4 Bat Man 5 5 1 5 Spider Man
  • 25. Conventions at Work articles id title body 1 Unique … comments id article_id body 1 1 First!
  • 26. Conventions at Work Rails favors conventions articles id title body 1 Unique … comments id article_id body 1 1 First!
  • 27. Conventions at Work Rails favors conventions articles With associations: id title body 1 Unique … comments id article_id body 1 1 First!
  • 28. Conventions at Work Rails favors conventions articles With associations: id title body Auto-incremented ID 1 Unique … fields comments id article_id body 1 1 First!
  • 29. Conventions at Work Rails favors conventions articles With associations: id title body Auto-incremented ID 1 Unique … fields Table name is plural comments for the collection id article_id body 1 1 First!
  • 30. Conventions at Work Rails favors conventions articles With associations: id title body Auto-incremented ID 1 Unique … fields Table name is plural comments for the collection id article_id body Foreign key is a singular item plus _id 1 1 First!
  • 31. Associations, Rails Style Let’s turn those examples into real Rails code
  • 33. Rails Macros Use belongs_to() on the ID side of a one to one or one to many
  • 34. Rails Macros Use belongs_to() on the ID side of a one to one or one to many Use has_one() on the other side of a one to one
  • 35. Rails Macros Use belongs_to() on the ID side of a one to one or one to many Use has_one() on the other side of a one to one Use has_many() on the other side of a one to many
  • 36. Rails Macros Use belongs_to() on the ID side of a one to one or one to many Use has_one() on the other side of a one to one Use has_many() on the other side of a one to many Use two belongs_to() calls for the join model of a many to many
  • 37. Rails Macros Use belongs_to() on the ID side of a one to one or one to many Use has_one() on the other side of a one to one Use has_many() on the other side of a one to many Use two belongs_to() calls for the join model of a many to many Use has_many() and has_many(…, :through => …) for the data models of a many to many
  • 38. One to Many articles id title body comments 1 The CRUD … id article_id body 2 Associations … 1 1 First! 2 1 Tard. 3 1 Am not! 4 2 Viagra 5 2 Spam!
  • 39. One to Many An article has_many() comments
  • 40. class Article < ActiveRecord::Base has_many :comments end class Comment < ActiveRecord::Base belongs_to :article end One to Many An article has_many() comments
  • 41. Associated Models You can query through the association
  • 42. >> crud = Article.first => #<Article id: 1, title: "The CRUD", body: "...", …> >> crud.comments.count => 3 >> crud.comments => [#<Comment id: 1, article_id: 1, body: "First!", …>, #<Comment id: 2, article_id: 1, body: "Tard.", …>, #<Comment id: 3, article_id: 1, body: "Am not!", …>] >> crud.comments.last => #<Comment id: 3, article_id: 1, body: "Am not!", …> >> crud.comments.last.article => #<Article id: 1, title: "The CRUD", body: "...", …> Associated Models You can query through the association
  • 43. >> crud = Article.first => #<Article id: 1, title: "The CRUD", body: "...", …> >> crud.comments.count => 3 >> crud.comments => [#<Comment id: 1, article_id: 1, body: "First!", …>, #<Comment id: 2, article_id: 1, body: "Tard.", …>, #<Comment id: 3, article_id: 1, body: "Am not!", …>] >> crud.comments.last => #<Comment id: 3, article_id: 1, body: "Am not!", …> >> crud.comments.last.article => #<Article id: 1, title: "The CRUD", body: "...", …> Associated Models You can query through the association
  • 44. >> crud = Article.first => #<Article id: 1, title: "The CRUD", body: "...", …> >> crud.comments.count => 3 >> crud.comments => [#<Comment id: 1, article_id: 1, body: "First!", …>, #<Comment id: 2, article_id: 1, body: "Tard.", …>, #<Comment id: 3, article_id: 1, body: "Am not!", …>] >> crud.comments.last => #<Comment id: 3, article_id: 1, body: "Am not!", …> >> crud.comments.last.article => #<Article id: 1, title: "The CRUD", body: "...", …> Associated Models You can query through the association
  • 45. >> crud = Article.first => #<Article id: 1, title: "The CRUD", body: "...", …> >> crud.comments.count => 3 >> crud.comments => [#<Comment id: 1, article_id: 1, body: "First!", …>, #<Comment id: 2, article_id: 1, body: "Tard.", …>, #<Comment id: 3, article_id: 1, body: "Am not!", …>] >> crud.comments.last => #<Comment id: 3, article_id: 1, body: "Am not!", …> >> crud.comments.last.article => #<Article id: 1, title: "The CRUD", body: "...", …> Associated Models You can query through the association
  • 46. >> crud = Article.first => #<Article id: 1, title: "The CRUD", body: "...", …> >> crud.comments.count => 3 >> crud.comments => [#<Comment id: 1, article_id: 1, body: "First!", …>, #<Comment id: 2, article_id: 1, body: "Tard.", …>, #<Comment id: 3, article_id: 1, body: "Am not!", …>] >> crud.comments.last => #<Comment id: 3, article_id: 1, body: "Am not!", …> >> crud.comments.last.article => #<Article id: 1, title: "The CRUD", body: "...", …> Associated Models You can query through the association
  • 47. Adding to an Association There are multiple ways to add in new models
  • 48. >> a = Article.create!(:title => "Needs Comments") => #<Article id: 3, title: "Needs Comments", body: nil, …> >> a.comments => [] >> a.comments.create!(:body => "create!()") => #<Comment id: 6, article_id: 3, body: "create!()", …> >> a.comments << Comment.new(:body => "<<") => [#<Comment id: 6, article_id: 3, body: "create!()", …>, #<Comment id: 7, article_id: 3, body: "<<", …>] >> c = a.comments.build(:body => "build()") => #<Comment id: nil, article_id: 3, body: "build()", created_at: nil, updated_at: nil> >> c.save! => true >> a.comments => [#<Comment id: 6, article_id: 3, body: "create!()", …>, #<Comment id: 7, article_id: 3, body: "<<", …>, #<Comment id: 8, article_id: 3, body: "build()", …>] Adding to an Association There are multiple ways to add in new models
  • 49. >> a = Article.create!(:title => "Needs Comments") => #<Article id: 3, title: "Needs Comments", body: nil, …> >> a.comments => [] >> a.comments.create!(:body => "create!()") => #<Comment id: 6, article_id: 3, body: "create!()", …> >> a.comments << Comment.new(:body => "<<") => [#<Comment id: 6, article_id: 3, body: "create!()", …>, #<Comment id: 7, article_id: 3, body: "<<", …>] >> c = a.comments.build(:body => "build()") => #<Comment id: nil, article_id: 3, body: "build()", created_at: nil, updated_at: nil> >> c.save! => true >> a.comments => [#<Comment id: 6, article_id: 3, body: "create!()", …>, #<Comment id: 7, article_id: 3, body: "<<", …>, #<Comment id: 8, article_id: 3, body: "build()", …>] Adding to an Association There are multiple ways to add in new models
  • 50. >> a = Article.create!(:title => "Needs Comments") => #<Article id: 3, title: "Needs Comments", body: nil, …> >> a.comments => [] >> a.comments.create!(:body => "create!()") => #<Comment id: 6, article_id: 3, body: "create!()", …> >> a.comments << Comment.new(:body => "<<") => [#<Comment id: 6, article_id: 3, body: "create!()", …>, #<Comment id: 7, article_id: 3, body: "<<", …>] >> c = a.comments.build(:body => "build()") => #<Comment id: nil, article_id: 3, body: "build()", created_at: nil, updated_at: nil> >> c.save! => true >> a.comments => [#<Comment id: 6, article_id: 3, body: "create!()", …>, #<Comment id: 7, article_id: 3, body: "<<", …>, #<Comment id: 8, article_id: 3, body: "build()", …>] Adding to an Association There are multiple ways to add in new models
  • 51. >> a = Article.create!(:title => "Needs Comments") => #<Article id: 3, title: "Needs Comments", body: nil, …> >> a.comments => [] >> a.comments.create!(:body => "create!()") => #<Comment id: 6, article_id: 3, body: "create!()", …> >> a.comments << Comment.new(:body => "<<") => [#<Comment id: 6, article_id: 3, body: "create!()", …>, #<Comment id: 7, article_id: 3, body: "<<", …>] >> c = a.comments.build(:body => "build()") => #<Comment id: nil, article_id: 3, body: "build()", created_at: nil, updated_at: nil> >> c.save! => true >> a.comments => [#<Comment id: 6, article_id: 3, body: "create!()", …>, #<Comment id: 7, article_id: 3, body: "<<", …>, #<Comment id: 8, article_id: 3, body: "build()", …>] Adding to an Association There are multiple ways to add in new models
  • 52. Deleting Associated Models To delete associated models, find normally and call destroy()
  • 53. >> a.comments => [#<Comment id: 6, article_id: 3, body: "create!()", …>, #<Comment id: 7, article_id: 3, body: "<<", …>, #<Comment id: 8, article_id: 3, body: "build()", …>] >> c = a.comments.find(8) => #<Comment id: 8, article_id: 3, body: "build()", …> >> c.destroy if c => #<Comment id: 8, article_id: 3, body: "build()", …> >> a.comments(true) => [#<Comment id: 6, article_id: 3, body: "create!()", …>, #<Comment id: 7, article_id: 3, body: "<<", …>] Deleting Associated Models To delete associated models, find normally and call destroy()
  • 54. >> a.comments => [#<Comment id: 6, article_id: 3, body: "create!()", …>, #<Comment id: 7, article_id: 3, body: "<<", …>, #<Comment id: 8, article_id: 3, body: "build()", …>] >> c = a.comments.find(8) => #<Comment id: 8, article_id: 3, body: "build()", …> >> c.destroy if c => #<Comment id: 8, article_id: 3, body: "build()", …> >> a.comments(true) => [#<Comment id: 6, article_id: 3, body: "create!()", …>, #<Comment id: 7, article_id: 3, body: "<<", …>] Deleting Associated Models To delete associated models, find normally and call destroy()
  • 55. >> a.comments => [#<Comment id: 6, article_id: 3, body: "create!()", …>, #<Comment id: 7, article_id: 3, body: "<<", …>, #<Comment id: 8, article_id: 3, body: "build()", …>] >> c = a.comments.find(8) => #<Comment id: 8, article_id: 3, body: "build()", …> >> c.destroy if c => #<Comment id: 8, article_id: 3, body: "build()", …> >> a.comments(true) => [#<Comment id: 6, article_id: 3, body: "create!()", …>, #<Comment id: 7, article_id: 3, body: "<<", …>] Deleting Associated Models To delete associated models, find normally and call destroy()
  • 56. >> a.comments => [#<Comment id: 6, article_id: 3, body: "create!()", …>, #<Comment id: 7, article_id: 3, body: "<<", …>, #<Comment id: 8, article_id: 3, body: "build()", …>] >> c = a.comments.find(8) => #<Comment id: 8, article_id: 3, body: "build()", …> >> c.destroy if c => #<Comment id: 8, article_id: 3, body: "build()", …> >> a.comments(true) => [#<Comment id: 6, article_id: 3, body: "create!()", …>, #<Comment id: 7, article_id: 3, body: "<<", …>] Deleting Associated Models To delete associated models, find normally and call destroy()
  • 58. Using Associations Correctly You should very rarely need to refer to an ID
  • 59. Using Associations Correctly You should very rarely need to refer to an ID Let Rails worry about that for you
  • 60. Using Associations Correctly You should very rarely need to refer to an ID Let Rails worry about that for you It’s safer to scope as many queries as possible through the association
  • 61. Using Associations Correctly You should very rarely need to refer to an ID Let Rails worry about that for you It’s safer to scope as many queries as possible through the association There’s less chance to affect the wrong data
  • 62. Using Associations Correctly You should very rarely need to refer to an ID Let Rails worry about that for you It’s safer to scope as many queries as possible through the association There’s less chance to affect the wrong data It adds security against users trying to spoof ID’s
  • 63. One to One users id first_name last_name 1 James Gray 2 Dana Gray photos id user_id path 1 1 /images/james.png
  • 64. One to One A user has_one() photo
  • 65. class User < ActiveRecord::Base has_one :photo end class Photo < ActiveRecord::Base belongs_to :user end One to One A user has_one() photo
  • 66. Model Attributes Just assign a belongs_to()/has_one() to set it (or call build_photo()/create_photo())
  • 67. >> james = User.find_by_first_name("James") => #<User id: 1, first_name: "James", last_name: "Gray", …> >> james.photo = Photo.new(:path => "/images/james.png") => #<Photo id: 1, user_id: 1, path: "/images/james.png", …> Model Attributes Just assign a belongs_to()/has_one() to set it (or call build_photo()/create_photo())
  • 68. >> james = User.find_by_first_name("James") => #<User id: 1, first_name: "James", last_name: "Gray", …> >> james.photo = Photo.new(:path => "/images/james.png") => #<Photo id: 1, user_id: 1, path: "/images/james.png", …> Model Attributes Just assign a belongs_to()/has_one() to set it (or call build_photo()/create_photo())
  • 69. photos Many to Many id path 1 /images/mac.jpg taggings 2 /images/pc.bmp id photo_id tag_id 1 1 1 tags id name 2 1 2 1 computer 3 1 3 2 sexy 4 2 4 3 lickable 4 junk
  • 70. Many to Many Photos have many tags
  • 71. class Photo < ActiveRecord::Base has_many :taggings has_many :tags, :through => :taggings end class Tagging < ActiveRecord::Base belongs_to :photo belongs_to :tag end class Tag < ActiveRecord::Base has_many :taggings has_many :photos, :through => :taggings end Many to Many Photos have many tags
  • 72. class Photo < ActiveRecord::Base has_many :taggings has_many :tags, :through => :taggings end class Tagging < ActiveRecord::Base belongs_to :photo belongs_to :tag end class Tag < ActiveRecord::Base has_many :taggings has_many :photos, :through => :taggings end Many to Many Photos have many tags
  • 73. has_many :through The nested association is mostly managed by Rails for you
  • 74. >> mac = Photo.first => #<Photo id: 1, user_id: 1, path: "/images/mac.jpg", …> >> mac.taggings => [#<Tagging id: 1, photo_id: 1, tag_id: 1, …>, #<Tagging id: 2, photo_id: 1, tag_id: 2, …>, #<Tagging id: 3, photo_id: 1, tag_id: 3, …>] >> mac.tags => [#<Tag id: 1, name: "computer", …>, #<Tag id: 2, name: "sexy", …>, #<Tag id: 3, name: "lickable", …>] >> pc = Photo.last => #<Photo id: 2, user_id: nil, path: "/images/pc.bmp", …> >> comp = Tag.find_or_create_by_name("computer") => #<Tag id: 1, name: "computer", …> >> pc.taggings.create!(:tag => comp) => #<Tagging id: 5, photo_id: 2, tag_id: 1, …> has_many :through The nested association is mostly managed by Rails for you
  • 75. >> mac = Photo.first => #<Photo id: 1, user_id: 1, path: "/images/mac.jpg", …> >> mac.taggings => [#<Tagging id: 1, photo_id: 1, tag_id: 1, …>, #<Tagging id: 2, photo_id: 1, tag_id: 2, …>, #<Tagging id: 3, photo_id: 1, tag_id: 3, …>] >> mac.tags => [#<Tag id: 1, name: "computer", …>, #<Tag id: 2, name: "sexy", …>, #<Tag id: 3, name: "lickable", …>] >> pc = Photo.last => #<Photo id: 2, user_id: nil, path: "/images/pc.bmp", …> >> comp = Tag.find_or_create_by_name("computer") => #<Tag id: 1, name: "computer", …> >> pc.taggings.create!(:tag => comp) => #<Tagging id: 5, photo_id: 2, tag_id: 1, …> has_many :through The nested association is mostly managed by Rails for you
  • 76. >> mac = Photo.first => #<Photo id: 1, user_id: 1, path: "/images/mac.jpg", …> >> mac.taggings => [#<Tagging id: 1, photo_id: 1, tag_id: 1, …>, #<Tagging id: 2, photo_id: 1, tag_id: 2, …>, #<Tagging id: 3, photo_id: 1, tag_id: 3, …>] >> mac.tags => [#<Tag id: 1, name: "computer", …>, #<Tag id: 2, name: "sexy", …>, #<Tag id: 3, name: "lickable", …>] >> pc = Photo.last => #<Photo id: 2, user_id: nil, path: "/images/pc.bmp", …> >> comp = Tag.find_or_create_by_name("computer") => #<Tag id: 1, name: "computer", …> >> pc.taggings.create!(:tag => comp) => #<Tagging id: 5, photo_id: 2, tag_id: 1, …> has_many :through The nested association is mostly managed by Rails for you
  • 77. >> mac = Photo.first => #<Photo id: 1, user_id: 1, path: "/images/mac.jpg", …> >> mac.taggings => [#<Tagging id: 1, photo_id: 1, tag_id: 1, …>, #<Tagging id: 2, photo_id: 1, tag_id: 2, …>, #<Tagging id: 3, photo_id: 1, tag_id: 3, …>] >> mac.tags => [#<Tag id: 1, name: "computer", …>, #<Tag id: 2, name: "sexy", …>, #<Tag id: 3, name: "lickable", …>] >> pc = Photo.last => #<Photo id: 2, user_id: nil, path: "/images/pc.bmp", …> >> comp = Tag.find_or_create_by_name("computer") => #<Tag id: 1, name: "computer", …> >> pc.taggings.create!(:tag => comp) => #<Tagging id: 5, photo_id: 2, tag_id: 1, …> has_many :through The nested association is mostly managed by Rails for you
  • 78. Many to Many (Two Tables) followings users id follower_id followed_id id first_name last_name 1 1 4 1 James Gray 2 2 4 2 Dana Gray 3 3 1 3 Super Man 4 4 1 4 Bat Man 5 5 1 5 Spider Man
  • 79. Many to Many (Two Tables) Users have many followers
  • 80. class Following < ActiveRecord::Base belongs_to :follower, :class_name => "User", :foreign_key => :follower_id belongs_to :followed, :class_name => "User", :foreign_key => :followed_id end class User < ActiveRecord::Base has_many :other_followings, :class_name => "Following", :foreign_key => :followed_id has_many :followers, :through => :other_followings has_many :self_followings, :class_name => "Following", :foreign_key => :follower_id has_many :followed_by, :through => :self_followings, :source => :followed end Many to Many (Two Tables) Users have many followers
  • 81. class Following < ActiveRecord::Base belongs_to :follower, :class_name => "User", :foreign_key => :follower_id belongs_to :followed, :class_name => "User", :foreign_key => :followed_id end class User < ActiveRecord::Base has_many :other_followings, :class_name => "Following", :foreign_key => :followed_id has_many :followers, :through => :other_followings has_many :self_followings, :class_name => "Following", :foreign_key => :follower_id has_many :followed_by, :through => :self_followings, :source => :followed end Many to Many (Two Tables) Users have many followers
  • 82. class Following < ActiveRecord::Base belongs_to :follower, :class_name => "User", :foreign_key => :follower_id belongs_to :followed, :class_name => "User", :foreign_key => :followed_id end class User < ActiveRecord::Base has_many :other_followings, :class_name => "Following", :foreign_key => :followed_id has_many :followers, :through => :other_followings has_many :self_followings, :class_name => "Following", :foreign_key => :follower_id has_many :followed_by, :through => :self_followings, :source => :followed end Many to Many (Two Tables) Users have many followers
  • 83. class Following < ActiveRecord::Base belongs_to :follower, :class_name => "User", :foreign_key => :follower_id belongs_to :followed, :class_name => "User", :foreign_key => :followed_id end class User < ActiveRecord::Base has_many :other_followings, :class_name => "Following", :foreign_key => :followed_id has_many :followers, :through => :other_followings has_many :self_followings, :class_name => "Following", :foreign_key => :follower_id has_many :followed_by, :through => :self_followings, :source => :followed end Many to Many (Two Tables) Users have many followers
  • 84. Two-way Relationships Once you get the relationships right, Rails can still manage the messy details
  • 85. >> james = User.find_by_first_name("James") => #<User id: 1, first_name: "James", last_name: "Gray", …> >> james.followers => [#<User id: 3, first_name: "Super", last_name: "Man", …>, #<User id: 4, first_name: "Bat", last_name: "Man", …>, #<User id: 5, first_name: "Spider", last_name: "Man", …>] >> james.followed_by => [#<User id: 4, first_name: "Bat", last_name: "Man", …>] >> bat = User.find_by_first_name("Bat") => #<User id: 4, first_name: "Bat", last_name: "Man", …> >> bat.followers => [#<User id: 1, first_name: "James", last_name: "Gray", …>, #<User id: 2, first_name: "Dana", last_name: "Gray", …>] Two-way Relationships Once you get the relationships right, Rails can still manage the messy details
  • 86. >> james = User.find_by_first_name("James") => #<User id: 1, first_name: "James", last_name: "Gray", …> >> james.followers => [#<User id: 3, first_name: "Super", last_name: "Man", …>, #<User id: 4, first_name: "Bat", last_name: "Man", …>, #<User id: 5, first_name: "Spider", last_name: "Man", …>] >> james.followed_by => [#<User id: 4, first_name: "Bat", last_name: "Man", …>] >> bat = User.find_by_first_name("Bat") => #<User id: 4, first_name: "Bat", last_name: "Man", …> >> bat.followers => [#<User id: 1, first_name: "James", last_name: "Gray", …>, #<User id: 2, first_name: "Dana", last_name: "Gray", …>] Two-way Relationships Once you get the relationships right, Rails can still manage the messy details
  • 87. >> james = User.find_by_first_name("James") => #<User id: 1, first_name: "James", last_name: "Gray", …> >> james.followers => [#<User id: 3, first_name: "Super", last_name: "Man", …>, #<User id: 4, first_name: "Bat", last_name: "Man", …>, #<User id: 5, first_name: "Spider", last_name: "Man", …>] >> james.followed_by => [#<User id: 4, first_name: "Bat", last_name: "Man", …>] >> bat = User.find_by_first_name("Bat") => #<User id: 4, first_name: "Bat", last_name: "Man", …> >> bat.followers => [#<User id: 1, first_name: "James", last_name: "Gray", …>, #<User id: 2, first_name: "Dana", last_name: "Gray", …>] Two-way Relationships Once you get the relationships right, Rails can still manage the messy details
  • 88. Extras Rails associations have quite a few options
  • 90. Finder Options and Dependance Set :conditions, :order, etc. on associations
  • 91. Finder Options and Dependance Set :conditions, :order, etc. on associations Example: :order => “created_at DESC”
  • 92. Finder Options and Dependance Set :conditions, :order, etc. on associations Example: :order => “created_at DESC” Specify what happens to associations with destroy()
  • 93. Finder Options and Dependance Set :conditions, :order, etc. on associations Example: :order => “created_at DESC” Specify what happens to associations with destroy() :dependent => :destroy forwards destroy()
  • 94. Finder Options and Dependance Set :conditions, :order, etc. on associations Example: :order => “created_at DESC” Specify what happens to associations with destroy() :dependent => :destroy forwards destroy() :dependent => :nullify breaks the link
  • 96. Polymorphic Associations Rails has a special type of “Polymorphic Association”
  • 97. Polymorphic Associations Rails has a special type of “Polymorphic Association” Models are linked with a type and an ID
  • 98. Polymorphic Associations Rails has a special type of “Polymorphic Association” Models are linked with a type and an ID This makes it possible to link one model to multiple different kinds of other models
  • 99. Polymorphic Associations Rails has a special type of “Polymorphic Association” Models are linked with a type and an ID This makes it possible to link one model to multiple different kinds of other models For example, you might use a Comment model to allows users to comment on multiple things (products and reviews for example)
  • 101. Fleshing out the Data Layer Lab Your book has instructions on how to add new models and associate them with existing tables