Ruby on Rails/ActiveRecord/Associations

Associations

edit

Introduction

edit

Associations are methods to connect 2 models. Operations on objects become quite simple. The association describes the role of relations that models are having with each other. ActiveRecord associations can be used to describe one-to-one (1:1), one-to-many (1:n) and many-to-many (n:m) relationships between models. There are several types of associations

  • belongs_to and
  • has_one form a one-to-one relationship
  • has_one :through is a different way to create a one-to-one relationship


  • has_many and
  • belongs_to form a one-to-many relation


  • has_and_belongs_to_many or an alternative way
  • has_many :through to create a many-to-many relationship

For all following examples, we assume the following 4 models:

class Product < ActiveRecord::Base
end

class Category < ActiveRecord::Base
end

class Rating < ActiveRecord::Base
end

class Tag < ActiveRecord::Base
end

Also check out the ER-diagram for the models below:

 

belongs_to

edit

The belongs_to association sets up an one-to-one (1:1) or one-to-many (1:n) relationship to an other model.

In our example, one Rating belongs to exactly one Product, so we need to set up a belongs_to association.

class Product < ActiveRecord::Base
  belongs_to :rating
end

The product stores an id for a rating, both of them have a one-to-one Relationship. Meaning: One product belongs to one category and one product belongs to one rating.

has_one

edit

The has_one association is a one-to-one relation too. It declares that each instance of a product from the productmodel possesses only one rating_id.

class Rating< ActiveRecord::Base
  has_one :product
end

Since the rating and the product form a one-to-one relationship, it is up to us where we put the reference. Because we have put the reference (the rating_id) into the product (see belongs_to :rating into the product model), the association for the rating has to be has_one:product. Has_one and belongs_to always go together to form a relationship.

has_many

edit

This is a one-to-many connection to an other model. In this case, one category has many products. Pay attention to the spelling, if you use has_many. The model that you want to reference needs to be written in plural.

class Category< ActiveRecord::Base
  has_many :products #note the plural here!
end

class Product< ActiveRecord::Base
  belongs_to :category
end

The category and the product are forming a one-to-many relationship. Since a category has many products we put the has_many association inside the category. Note that also the product needs to contain a reference to the category. One product belongs to exactly one category, therefore we put belongs_to :category inside the product model.

has_and_belongs_to_many

edit

Also known asĀ : HABTM.

Has_and_belongs_to_many is the most complex association. You need to keep some things in mind: Because of the way relational databases work, you can not set up a direct relationship. You need to create a joining table. This is easily done with migrations. If we want to create a HABTM association for our product and tag, the association for the joining table might look like following:

class CreateProductTagJoinTable < ActiveRecord::Migration
  def self.up
   create_table :products_tags, :id => false do |t| #we DO NOT need the id here!
     t.integer :product_id #alternatively, we can write t.references :product
     t.integer :tag_id
   end
  end

  def self.down
    drop_table :products_tags
  end
end

Because we do not need a primary key inside the join table, we use :id => false to prevent the automatic creation of a primary key column. The naming of the table needs to be in alphabetical order. "P" is before "T" in the alphabet so the tablename has to be products_tags (note: plural).

class Product< ActiveRecord::Base
  has_and_belongs_to_many :tags
end

class Tag< ActiveRecord::Base
   has_and_belongs_to_many :products
end

has_many :through

edit

This association is an other way to form a many-to-many relation. Consider the following ER-Diagramm to show the relationship.

 

class Product < ActiveRecord::Base
  belongs_to :category
  belongs_to :supplier
end

class Supplier < ActiveRecord::Base
  has_many :products
  has_many :categories, :through => :products
end

class Category< ActiveRecord::Base
  has_many :products
  has_many :suppliers, :through => :products
end

Instead of using a join table we use another model for the relationship. If we want to find out which supplier is responsible for a specific category we need the product to link the models together. This way we can store additional data inside a real model that also acts as a joining model. Whenever you need to store data that additionally belongs to association (e.g. the date of the creation) you might want to use this type of association.

has_one :through

edit

As with has_many :through, the has_one :through association uses an "extra" model to form a relation.

Consider this visual relationship:

 

class Network < ActiveRecord::Base
  has_one :group
  has_one :user, :through =>:group
end

class Group < ActiveRecord::Base
  belongs_to :network
  has_one :user
end

class User< ActiveRecord::Base
  belongs_to :group
end

Note: This example assumes that the membership inside a group is exclusive for each user.