SlideShare a Scribd company logo
1 of 101
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

In the Back of Your Mind
In the Back of Your MindIn the Back of Your Mind
In the Back of Your MindJames Gray
 
Amazon's Simple Storage Service (S3)
Amazon's Simple Storage Service (S3)Amazon's Simple Storage Service (S3)
Amazon's Simple Storage Service (S3)James Gray
 
Git and GitHub
Git and GitHubGit and GitHub
Git and GitHubJames Gray
 
Test Coverage in Rails
Test Coverage in RailsTest Coverage in Rails
Test Coverage in RailsJames Gray
 
Rails Routing And Rendering
Rails Routing And RenderingRails Routing And Rendering
Rails Routing And RenderingJames Gray
 
Sending Email with Rails
Sending Email with RailsSending Email with Rails
Sending Email with RailsJames Gray
 
DRYing Up Rails Views and Controllers
DRYing Up Rails Views and ControllersDRYing Up Rails Views and Controllers
DRYing Up Rails Views and ControllersJames Gray
 
Building a Rails Interface
Building a Rails InterfaceBuilding a Rails Interface
Building a Rails InterfaceJames Gray
 
Wed Development on Rails
Wed Development on RailsWed Development on Rails
Wed Development on RailsJames Gray
 

More from James Gray (13)

In the Back of Your Mind
In the Back of Your MindIn the Back of Your Mind
In the Back of Your Mind
 
Unblocked
UnblockedUnblocked
Unblocked
 
Module Magic
Module MagicModule Magic
Module Magic
 
API Design
API DesignAPI Design
API Design
 
Amazon's Simple Storage Service (S3)
Amazon's Simple Storage Service (S3)Amazon's Simple Storage Service (S3)
Amazon's Simple Storage Service (S3)
 
Git and GitHub
Git and GitHubGit and GitHub
Git and GitHub
 
Test Coverage in Rails
Test Coverage in RailsTest Coverage in Rails
Test Coverage in Rails
 
Rails Routing And Rendering
Rails Routing And RenderingRails Routing And Rendering
Rails Routing And Rendering
 
Sending Email with Rails
Sending Email with RailsSending Email with Rails
Sending Email with Rails
 
DRYing Up Rails Views and Controllers
DRYing Up Rails Views and ControllersDRYing Up Rails Views and Controllers
DRYing Up Rails Views and Controllers
 
Building a Rails Interface
Building a Rails InterfaceBuilding a Rails Interface
Building a Rails Interface
 
Ruby
RubyRuby
Ruby
 
Wed Development on Rails
Wed Development on RailsWed Development on Rails
Wed Development on Rails
 

Recently uploaded

A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI AgeCprime
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxLoriGlavin3
 
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfSo einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfpanagenda
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Strongerpanagenda
 
Zeshan Sattar- Assessing the skill requirements and industry expectations for...
Zeshan Sattar- Assessing the skill requirements and industry expectations for...Zeshan Sattar- Assessing the skill requirements and industry expectations for...
Zeshan Sattar- Assessing the skill requirements and industry expectations for...itnewsafrica
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...Wes McKinney
 
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Nikki Chapple
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxLoriGlavin3
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxGenerative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxfnnc6jmgwh
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesThousandEyes
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Hiroshi SHIBATA
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsNathaniel Shimoni
 
Testing tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesTesting tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesKari Kakkonen
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 

Recently uploaded (20)

A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI Age
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
 
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfSo einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
 
Zeshan Sattar- Assessing the skill requirements and industry expectations for...
Zeshan Sattar- Assessing the skill requirements and industry expectations for...Zeshan Sattar- Assessing the skill requirements and industry expectations for...
Zeshan Sattar- Assessing the skill requirements and industry expectations for...
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
 
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptxGenerative AI - Gitex v1Generative AI - Gitex v1.pptx
Generative AI - Gitex v1Generative AI - Gitex v1.pptx
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directions
 
Testing tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesTesting tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examples
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 

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

Editor's Notes