Ruby on Rails/ActiveRecord/Associations
Associations
editIntroduction
editAssociations 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
editThe 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
editThe 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
editThis 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
editAlso 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
editThis 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
editAs 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.