# Relationships

  • Introduction

    Database tables are often related to one another. For example, a blog post may have many comments or an order could be related to the user who placed it. Active Record makes managing and working with these relationships easy, and supports a variety of common relationships:

    • One To One
    • One To Many
    • Many To Many
    • Has One Through
    • Has Many Through
    • One To One (Polymorphic)
    • One To Many (Polymorphic)
    • Many To Many (Polymorphic)
  • Relations

    • One to One

      A one-to-one relationship is a very basic type of database relationship. For example, a User model might be associated with one **Phone**model. To define this relationship, we will place a has_one phone on the **User**model.

      class User < ApplicationRecord
        has_one :phone
      end
      
      1
      2
      3
      class Phone < ApplicationRecord
         validates_uniqueness_of :user_id, message: "can not have more than one phone"
      end
      
      1
      2
      3

      The corresponding migration might look like this:

      class CreateUsers < ActiveRecord::Migration[7.0]
        def change
          create_table :users do |t|
            t.string :name
            t.timestamps
          end
      
          create_table :phones do |t|
            t.belongs_to :user
            t.string :phone_number
            t.timestamps
          end
        end
      end
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14

      Depending on the use case, you might also need to create a unique index and/or a foreign key constraint on the supplier column for the accounts table. In this case, the column definition might look like this:

      create_table :phones do |t|
        t.belongs_to :user, index: { unique: true }, foreign_key: true
        # ...
      end
      
      1
      2
      3
      4

      In order to link the resource , you can do by

      Phone.create({user: User.find(1) , phone_number:'9823432543'})
      
      #You can also provide id direct
      Phone.create({user_id: 1 , phone_number:'9823432543'})
      
      1
      2
      3
      4

      You can access the associated relation by

      phone = User.find(1).phone
      
      1

      Defining inverse of relation:

      So, we can access the **Phone**model from our **User**model. Next, let's define a relationship on the **Phone**model that will let us access the user that owns the phone. We can define the inverse of a **has_one**relationship using the belongs_to method:

      class Phone < ApplicationRecord
        belongs_to :user
      end
      
      1
      2
      3
    • One to Many

      A one-to-many relationship is used to define relationships where a single model is the parent to one or more child models. For example, a blog post may have an infinite number of comments. Like all other Active record relationships, one-to-many relationships are defined by defining a method on your Active record model:

      class Post < ApplicationRecord
        has_many :comments
      end
      
      1
      2
      3

      The corresponding migration might look like this:

      class CreatePosts < ActiveRecord::Migration[7.0]
        def change
          create_table :posts do |t|
            t.string :title
            t.timestamps
          end
      
          create_table :comments do |t|
            t.belongs_to :post
            t.datetime :published_at
            t.timestamps
          end
        end
      end
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14

      Depending on the use case, it's usually a good idea to create a non-unique index and optionally a foreign key constraint on the author column for the books table:

      create_table :comments do |t|
        t.belongs_to :post, index: true, foreign_key: true
        # ...
      end
      
      1
      2
      3
      4

      You can access the associated relation by

      comments = Post.find(1).comments
      
      1
    • Has One Through

      [has_one :through](https://api.rubyonrails.org/v7.0.4/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_one) association sets up a one-to-one connection with another model. This association indicates that the declaring model can be matched with one instance of another model by proceeding through a third model. For example, if each supplier has one account, and each account is associated with one account history, then the supplier model could look like this:

      class Supplier < ApplicationRecord
        has_one :account
        has_one :account_history, through: :account
      end
      
      class Account < ApplicationRecord
        belongs_to :supplier
        has_one :account_history
      end
      
      class AccountHistory < ApplicationRecord
        belongs_to :account
      end
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13

      The corresponding migration might look like this:

      class CreateAccountHistories < ActiveRecord::Migration[7.0]
        def change
          create_table :suppliers do |t|
            t.string :name
            t.timestamps
          end
      
          create_table :accounts do |t|
            t.belongs_to :supplier
            t.string :account_number
            t.timestamps
          end
      
          create_table :account_histories do |t|
            t.belongs_to :account
            t.integer :credit_rating
            t.timestamps
          end
        end
      end
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
  • Many to Many

    • Has Many Through

      [has_many :through](https://api.rubyonrails.org/v7.0.4/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many) association is often used to set up a many-to-many connection with another model. This association indicates that the declaring model can be matched with zero or more instances of another model by proceeding through a third model. For example, consider a medical practice where patients make appointments to see physicians. The relevant association declarations could look like this:

      class Physician < ApplicationRecord
        has_many :appointments
        has_many :patients, through: :appointments
      end
      
      class Appointment < ApplicationRecord
        belongs_to :physician
        belongs_to :patient
      end
      
      class Patient < ApplicationRecord
        has_many :appointments
        has_many :physicians, through: :appointments
      end
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14

      The corresponding migration might look like this:

      class CreateAppointments < ActiveRecord::Migration[7.0]
        def change
          create_table :physicians do |t|
            t.string :name
            t.timestamps
          end
      
          create_table :patients do |t|
            t.string :name
            t.timestamps
          end
      
          create_table :appointments do |t|
            t.belongs_to :physician
            t.belongs_to :patient
            t.datetime :appointment_date
            t.timestamps
          end
        end
      end
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20

      The collection of join models can be managed via the [has_many association methods](https://guides.rubyonrails.org/association_basics.html#has-many-association-reference) . For example, if you assign:

      physician.patients = patients
      
      1

      Then new join models are automatically created for the newly associated objects. If some that existed previously are now missing, then their join rows are automatically deleted.

    • has and belongs to many

      [has_and_belongs_to_many](https://api.rubyonrails.org/v7.0.4/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_and_belongs_to_many) association creates a direct many-to-many connection with another model, with no intervening model. This association indicates that each instance of the declaring model refers to zero or more instances of another model. For example, if your application includes assemblies and parts, with each assembly having many parts and each part appearing in many assemblies, you could declare the models this way:

      class Assembly < ApplicationRecord
        has_and_belongs_to_many :parts
      end
      
      class Part < ApplicationRecord
        has_and_belongs_to_many :assemblies
      end
      
      1
      2
      3
      4
      5
      6
      7

      The corresponding migration might look like this:

      class CreateAssembliesAndParts < ActiveRecord::Migration[7.0]
        def change
          create_table :assemblies do |t|
            t.string :name
            t.timestamps
          end
      
          create_table :parts do |t|
            t.string :part_number
            t.timestamps
          end
      
          create_table :assemblies_parts, id: false do |t|
            t.belongs_to :assembly
            t.belongs_to :part
          end
        end
      end
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
  • Polymorphic Relationships

    A slightly more advanced twist on associations is the polymorphic association. With polymorphic associations, a model can belong to more than one other model, on a single association. For example, you might have a picture model that belongs to either an employee model or a product model. Here's how this could be declared:

    class Picture < ApplicationRecord
      belongs_to :imageable, polymorphic: true
    end
    
    class Employee < ApplicationRecord
      has_many :pictures, as: :imageable
    end
    
    class Product < ApplicationRecord
      has_many :pictures, as: :imageable
    end
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    You can think of a polymorphic belongs_to declaration as setting up an interface that any other model can use. From an instance of the Employee model, you can retrieve a collection of pictures: @employee.pictures.

    Similarly, you can retrieve @product.pictures.

    If you have an instance of the Picture model, you can get to its parent via @picture.imageable. To make this work, you need to declare both a foreign key column and a type column in the model that declares the polymorphic interface:

    class CreatePictures < ActiveRecord::Migration[7.0]
      def change
        create_table :pictures do |t|
          t.string  :name
          t.bigint  :imageable_id
          t.string  :imageable_type
          t.timestamps
        end
    
        add_index :pictures, [:imageable_type, :imageable_id]
      end
    end
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    This migration can be simplified by using the t.references form:

    class CreatePictures < ActiveRecord::Migration[7.0]
      def change
        create_table :pictures do |t|
          t.string :name
          t.references :imageable, polymorphic: true
          t.timestamps
        end
      end
    end
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
  • Self Joins

    In designing a data model, you will sometimes find a model that should have a relation to itself. For example, you may want to store all employees in a single database model, but be able to trace relationships such as between manager and subordinates. This situation can be modeled with self-joining associations:

    class Employee < ApplicationRecord
      has_many :subordinates, class_name: "Employee",
                              foreign_key: "manager_id"
    
      belongs_to :manager, class_name: "Employee", optional: true
    end
    
    1
    2
    3
    4
    5
    6

    With this setup, you can retrieve @employee.subordinates and @employee.manager.

    In your migrations/schema, you will add a references column to the model itself.

    class CreateEmployees < ActiveRecord::Migration[7.0]
      def change
        create_table :employees do |t|
          t.references :manager, foreign_key: { to_table: :employees }
          t.timestamps
        end
      end
    end
    
    1
    2
    3
    4
    5
    6
    7
    8