Ruby on Rails/ActiveRecord/Associations
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-diagramm for the models below:
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.
The has_one assocation 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.
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.
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
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.
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 exlusive for each user.