From time to time I’ve noticed people who struggle with cardinality and associations in Ruby on Rails. So, I thought I would attempt to create a cheat sheet here to help developers understand relationship cardinality and how it maps to associations.
ActiveRecord can be used to describe relations with one-to-one, one-to-many and many-to-many cardinality; where each model defines its relation to another. Let’s cover each of the three types of associations.
Use `has_one` in the base and `belongs_to` in the association:
class Family < ActiveRecord::Base has_one :home end class Home < ActiveRecord::Base belongs_to :family end
A common question about a one-to-one association is ‘how to know which direction the has_one and belongs_to go?’ The correct way to know, is that whichever model has the foreign key, gets the `belongs_to`. In this case, Home has the foreign key `family_id`.
One-to-one relationships are a bit odd, and as a general rule, if you find yourself using a lot of them, there is probably a better solution.
Use `has_many` in the base and `belongs_to` in the association:
class Family < ActiveRecord::Base has_many :parents end class Parent < ActiveRecord::Base belongs_to :family end
This will be your most common relationship. As with one-to-one’s, the table with the foreign key gets the `belongs_to` (although this is a lot more obvious with a one-to-many). In this case the foreign key is `family_id`.
These can be a lot more complicated and there is actually a couple of different ways to do it.
The first way involves a specific joining model. This results in 2 stages of has_many associations. It is referred to as `has_many :through` and is primarily used if you need to fully control the joining model/table:
class Family < ActiveRecord::Base belongs_to :parent belongs_to :kid end class Parent < ActiveRecord::Base has_many :kids, through: :families end class Kid < ActiveRecord::Base has_many :parents, through: :families end
The second (and my preferred way) is to use the `has_and_belongs_to_many` method:
class Parent < ActiveRecord::Base has_and_belongs_to_many :kids end class Kid < ActiveRecord::Base has_and_belongs_to_many :parents end
The main difference (or disadvantage) with the `has_and_belongs_to_many`method is that the intermediary joining table and foreign keys need to be exactly named to match what Rails expects. Which many-to-many method you use ultimately depends on whether you need to work with the relationship model as its own entity directly.