ActiveRecord associations and more Part 1

Ali Erbay
4 min readSep 14, 2020

Ruby on Rails has an application directory called app/ with three subdirectories: models, views, and controllers. In this article, we are going to focus on “models” which are controlled by Active Record.

Active Record creates and uses objects whose data requires persistent storage to a database. It is an implementation of the Active Record pattern which itself is a description of an Object Relational Mapping system. Active Record lets developers use Ruby DSL and easily manipulate or query database compared to cumbersome SQL syntax.

Active Record gives us several mechanisms, the most important being the ability to:

  • Represent models and their data.
  • Represent associations between these models.
  • Represent inheritance hierarchies through related models.
  • Validate models before they get persisted to the database.
  • Perform database operations in an object-oriented fashion.

We are going to focus on Association types that define the Active Record relationship between two or more models. Each type associates a specific relationship that connects models together. So preparing your database schema becomes like a puzzle to solve, you need to define your models then you are required to select the type of associations between them. This can become quite tricky when you have a complex business model to create in Active Record.

Rails support six types of associations:

  • belongs_to
  • has_one
  • has_many
  • has_many :through
  • has_one :through
  • has_and_belongs_to_many

belongs_to

A belongs_to association sets up a 1-to-1 relation with another model, meaning that each instance of the declaring model belongs to one instance of the other model. For instance, if your business model includes Albums and Artists, and each Album can be assigned to exactly one Artist

Note that we are using “artist” as singular not “artists” plural. This method can be used only if this class contains the foreign key.

The following methods will be available for the model;

  • association
  • association=(associate)
  • build_association(attributes = {})
  • create_association(attributes = {})
  • create_association!(attributes = {})
  • reload_association

association is replaced with the symbol passed as the first argument to belongs_to in our example, it is “artist”.

has_one

has_one association is setup similar to belongs_to but unlike belongs_to association, has_one association tells us that every instance of a model contains only one instance of other model.

Same as belongs_to following methods will be available for the model;

  • association
  • association=(associate)
  • build_association(attributes = {})
  • create_association(attributes = {})
  • create_association!(attributes = {})
  • reload_association

has_many

A has_many association tells us that the model has a one-to-many connection with another model. This association is common to see on the opposite side of a belongs_to association. This association indicates that each instance of the model has zero or more instances of another model. For instance, in a business model containing Artists and Albums, the Artist model could be declared like following;

Note that we are using “albums” as plural not “album” singular. An instance of this model will have access to an array of objects containing multiple instances of the model belonging to it.

After declaring has_many association, the declaring class automatically gains 17 methods related to the association:

  • collection
  • collection<<(object, ...)
  • collection.delete(object, ...)
  • collection.destroy(object, ...)
  • collection=(objects)
  • collection_singular_ids
  • collection_singular_ids=(ids)
  • collection.clear
  • collection.empty?
  • collection.size
  • collection.find(...)
  • collection.where(...)
  • collection.exists?(...)
  • collection.build(attributes = {}, ...)
  • collection.create(attributes = {})
  • collection.create!(attributes = {})
  • collection.reload

has_many :through

Now we are getting into very useful and powerful associations. A has_many :through association sets up a many-to-many(n-n) connection with another model, indicating that the declaring model can be matched with multiple instances of another model through a third model. For instance, in a album collection web app where users owns albums and have reviews on them, association declarations would look like this:

Review model is a independent join model whose instances must have foreign key of a user and an album and its index key.

@user.reviewed_albums will reach out review join model and get corresponding album foreign keys for each user foreign key. @album.reviewers will do the same process to get users.

has_one :through

Very close to has_many :through but as the name suggests this kind of association sets up one-to-one relationship with another model;

has_and_belongs_to_many

A has_and_belongs_to_many association creates a direct many-to-many connection with another model. In this case, no third or intervening model is needed like in has_many :through association.

Under the hood, this is actually just another version of has_many :through, but the connector is a join table instead of a “real” model. We don’t create another third model class to represent it.

I believe Active Record what makes Rails so attractive since it handles database relations in a very smooth and easy way to grasp, it is very intuitive.

On the second part of the series, We will discuss Polymorphic associations and making a decision regarding selection between has_and_belongs_to_many and has_many :through

See you on the next part!

--

--

Ali Erbay

Full Stack Developer BDD/TDD || Ruby on Rails || React || React Native || NodeJS || Express https://github.com/kermit-klein