Rails Active Record Connection

has_many connection

A has_many relationship indicates a one-to-many connection to another model. This relationship is often on the “other side” of the belongs_to relationship. This relationship indicates that each model instance has zero or more instances of another model. For example, in an application containing authors and books, the author model might be declared like this:

classAuthor<ApplicationRecord

  has_many:books

end

NOTE: The name of the other model is plural when declaring the has_many relationship.

Diagram for has_many connection

The corresponding migration might look like this:

class CreateAuthors < ActiveRecord::Migration[5.0]

  def change

    create_table :authors do |t|

      t.string :name

      t.timestamps

    end

(the-has-many-through-association) has_many :through association

A has_many :through relationship is often used to set up a many-to-many connection with another model. This relationship indicates that the declaring model can match zero or more instances of another model via a third model. For example, consider a polyclinic where patients are given appointments to see physicians (physicians). The corresponding link declarations would 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

The collection of connection models can be managed using the has_many connection methods. For example, if you assign:

physician.patients = patients

Then new connection models for newly connected objects will be automatically created. If some of the previously existing ones are now missing, their connector strings are automatically removed.

WARNING: Automatic deletion of join models is straightforward, none of the kill callbacks are included.

The has_many :through relationship is also useful for setting “shortcuts” through nested has_many relationships. For example, if a document has many sections, and a section has many paragraphs, sometimes you want to get just a collection of all the paragraphs in the document. This can be configured like this:

With through: :sections defined, Rails now understands:

@document.paragraphs

(the-has-one-through-association) has_one :through association

The has_one :through relationship sets up a one-to-one connection with another model. This relationship indicates that the declaring model can be related to one instance of another model through a third model. For example, if each supplier has one account, and each account is associated with one account history, then the models might look like this:

The corresponding migration might look like this:

has_and_belongs_to_many relationship

A has_and_belongs_to_many relationship creates a direct many-to-many connection to another model, with no intermediate model. For example, if your application includes assemblies and parts (parts), where each node has many parts, and each part occurs in many assemblies, the models can be declared like this:

class Assembly < ApplicationRecord

  has_and_belongs_to_many :parts

end

class Part<ApplicationRecord

  has_and_belongs_to_many :assemblies

end

Diagram for has_and_belongs_to_many relationship

The corresponding migration might look like this:

class CreateAssembliesAndParts < ActiveRecord::Migration[5.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, index: true

      t.belongs_to :part, index: true

    end

  end

end

Choice between belongs_to and has_one

If you want to set up a one-to-one relationship between two models, you need to add belongs_to to one and has_one to the other. How to find out which is which?

The difference is where the foreign key is placed (it must be in the table for the class declaring the belongs_to relationship), but you also have to think about the actual meaning of the data. The has_one relation says that something belongs to you – that is, that something points to you. For example, it makes more sense that the supplier owns the account than that the account owns the supplier. This means that the correct relationship is like this:

class Supplier < ApplicationRecord

  has_one :account

end

class Account < ApplicationRecord

  belongs_to :supplier

end

The corresponding migration might look like this:

class CreateSuppliers < ActiveRecord::Migration[5.0]

  def change

    create_table :suppliers do |t|

      t.string :name

      t.timestamps

    end

    create_table :accounts do |t|

      t.integer :supplier_id

      t.string :account_number

      t.timestamps

    end

    add_index :accounts, :supplier_id

  end

end

NOTE: The use of t.integer :supplier_id specifies the foreign key name explicitly and explicitly. In modern versions of Rails, you can abstract away implementation details using t.references :supplier.

Choosing between has_many :through and has_and_belongs_to_many

Rails provides two different ways to declare a many-to-many relationship between models. The simplest way is to use has_and_belongs_to_many which allows you to create a relationship directly:

class Assembly < ApplicationRecord

  has_and_belongs_to_many :parts

end

class Part<ApplicationRecord

  has_and_belongs_to_many :assemblies

end

The second way to declare a many-to-many relationship is to use has_many :through. This does not communicate directly, but through a connecting model:

class Assembly < ApplicationRecord

  has_many :manifests

  has_many :parts, through: :manifests

end

class Manifest < ApplicationRecord

  belongs_to :assembly

  belongs_to :part

end

class Part<ApplicationRecord

  has_many :manifests

  has_many :assemblies, through: :manifests

end

The simplest sign that you need to set up a has_many :through relationship is if you want to treat the relationship model as an independent entity. If you don’t need to do anything with the relationship model, it’s easier to set up a has_and_belongs_to_many relationship (though remember to create a join table in the database).

You should use has_many :through if you need validations, callbacks, or additional attributes for the join model.

(polymorphic-associations)

Polymorphic relationships are a slightly more “fancy” kind of relationship. With polymorphic relationships, a model can belong to more than one model, on a single relationship. For example, there is an image model that belongs to either a worker model or a product model. Here’s how it’s 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

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 get a collection of images: @employee.pictures.

Similarly, you can get @product.pictures.

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

class CreatePictures < ActiveRecord::Migration[5.0]

  def change

    create_table :pictures do |t|

      t.string :name

      t.integer :imageable_id

      t.string :imageable_type

      t.timestamps

    end

    add_index :pictures, [:imageable_type, :imageable_id]

  end

end

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

Leave a Reply

Your email address will not be published.