Oct 21, 2015
Table of contents:
Last week we looked at getting started with Active Record in Ruby on Rails.
Rails’ implementation of the Active Record pattern is a big reason why the framework is approachable for beginners, yet powerful for professionals.
The Active Record pattern encapsulates database access and business logic as a single object. An important part of this is how objects are associated to other objects and subsequently mapped in the database.
In today’s tutorial we will be looking at Active Record Associations in Ruby on Rails.
If you’re reading this tutorial I’m going to assume you are already familiar with the common relationship patterns of relational databases.
The first thing to understand is how to define a relationship on an Active Record model. Here’s how you do it:
class Article < ActiveRecord.base
has_many :comments
end
If you are new to programming, the above code has probably went straight over your head, and if you are coming to Ruby from another language you’re probably thinking, “what on earth is going on here?”
To define an association in an Active Record model you use the Rails DSL.
In the example above, has_many
is simply a method that is invoked within the context of the current model.
The method accepts an argument (in this case :comments
). This is a symbol (What are Symbols in Ruby?).
When the object is loaded, Ruby will invoke the has_many
method and create the association automatically on the object.
This syntax seems kinda weird when you first start looking at Rails, it took me a while to get my head around, but it’s really just calling a method on the object.
Now any instance of Article
will have a comments
method that will hold the related comments for that record:
article = Article.find(123)
article.comments
In the section above we defined a has_many
relationship on the Article
model that relates to the Comment
model:
class Article < ActiveRecord.base
has_many :comments
end
The inverse of this relationship can be defined on the Comment
model like this:
class Comment < ActiveRecord.base
belongs_to :article
end
This allows you to access the Article
from the Comment
object:
comment = Comment.find(456)
comment.article
To add a Comment
to an Article
we can simply use regular Ruby code:
article.comments << Comment.create(body: 'Very interesting!')
A relationship where an object is associated to a single other object can be defined using the has_one
and belongs_to
methods:
class User < ActiveRecord::Base
has_one :avatar
end
class Avatar < ActiveRecord::Base
belongs_to :user
end
Once again, now that you’ve defined the relationship you will be able to access it through the associated instance method:
user = User.first
user.avatar.src
# => "profile-234.jpg"
Finally the most tricky relationship to get right is where many objects are related to many other objects. To do this we need an intermediate join table that sits in between the association.
This kind of relationship can be defined like this:
class Article < ActiveRecord::Base
has_many :taggings
has_many :tags, through: :taggings
end
As you can see, we are specifying that this relationship should go through the :taggings
association. So next we need to define that model:
class Tagging < ActiveRecord::Base
belongs_to :article
belongs_to :tag
end
Finally we can define the inverse of the relationship:
class Tag < ActiveRecord::Base
has_many :taggings
has_many :articles, through: :taggings
end
You can now access the tags through the tags
method:
article = Article.first
article.tags
Understanding the associations between models is a big step towards being able to build web applications.
One of the first steps when building a web application is usually gathering the specifications from the given requirements.
Being able to visualise, and then implement how the important entities of the applications are associated is an integral skill of this step.
Rails makes associating your models very easy. Your models will automatically gain the functionality of the defined association and they will automatically deal with translating from a relational database into a object context.