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!