Ruby on Rails/ActiveRecord/Associations
Associations[edit | edit source]
Introduction[edit | edit source]
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:
belongs_to[edit | edit source]
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 | edit source]
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 | edit source]
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 | edit source]
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 | edit source]
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 | edit source]
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.