It's a tried and true rule that working on something lends itself to your knowledge of whatever that thing is. If you cook a lot, you know more about cooking. Or if you've got hours of painting under your belt, it's a safe bet that you know a thing or two about mixing colors. Coding follows this same beautiful pattern. The more you code, the better you tend to be at it. The concepts governing coding and development get easier to grasp, and your code goes from a mangled and complicated exercise in mental acrobatics to clean, precise, and – most importantly – simple code of a line or two. Ah, simplicity. Ruby, in particular, is all about simplicity.
But as anyone learning code for the first time will tell you: you've gotta put in the hard work before it gets to be easy. Even the tools that are available to users with the explicit aim of simplifying their code and streamlining their workflow don't immediately lend themselves if the hard work of grounding oneself in core concepts has been shirked. It's important to know that our most important steps are our first steps, and our first steps should always be baby steps.
My baby step moment came when learning ActiveRecord. I thought I could skim through its docs (and there's never a shortage of them), cherrypick a few methods here and there, and build the next great big app.
Haha! Oh, dear reader, how I wish that had been the case. ActiveRecord, like all good things, required me to do my part in understanding what it was all about before it could become my new best friend. Part of that work for me was understanding associations.
Associations can be a tricky abstraction of an otherwise (seemingly) intuitive concept. Essentially, they are the connections between ruby models that express their distinct relationships and unique attributes. ActiveRecord lets us work with six kinds of associations: belongs_to, has_one, has_many, has_one :through, has_many :through & has_and_belongs_to_many. For today's short lesson, we'll be focusing on the three most commonly dealt with by beginner rubyists: belongs_to; has_many; and has_many, through:.
belongs_to & has_many
Let's say that I have two kids, Leah and Paulo. They are two individuals, but they are both children, and what's more, they are both my children. In ruby-speak, we can think of the kids as one model that has a relationship to me, the parent, another model. We can say that Leah belongs_to me and that Paulo belongs_to me too. I can also say, since two kids are more than one, that I have (er, has)_many kids. These two associations in ActiveRecord tend to come in pairs, with the "parent" class being the class that has_many instances of another class. Those instances, in this case, are my wonderfully fictional children, Leah & Paulo.
The relational databases (though for our purposes here, they are really just informative tables) above hopefully help clarify how ActiveRecord understands these associations. The class that belongs_to another class is the one that "holds the reference" to an instance of the parent class. This is represented by the "augusto" parent_id being present alongside both children instances (i.e., "Leah" and "Paulo"). This same column on the children table is the one that also lets the "augusto" instance of the parent class (Me!) know that it has_many children.
has_many, through:
Let's imagine Paulo and Leah are all grown up (it always happens so fast), and they've got little Paulo & Leah Jrs. of their own.
Suddenly, my little family has expanded. Now I can say that I (have) has_many grandchildren, through: (my) children. Suddenly, in ruby, we are dealing with a whole new model, grandchildren, that the parent class is able to access and know about through their relationship existent relationship with the children class.
In the image above, we can see the new table grandchildren and the effect it has had on the two other tables (no man is an island and no database is either). Now, not only do children instances belong_to an instance of parent, but they also (have) has_many grandchildren! Which, as we remember, in turn, belong_to their respective parent (or kid instance). We can see that the grandchildren class holds the reference to the kids class, which in turn holds the reference to the parent class. Again, also, we see that in order to establish these associations, we need to make sure each instance of a "referent" class knows "who" it's exactly related to by including the desired instance of a "main" class in their makeup.
It took me a few days to understand the relationship direction and flow between models that belong_to another model or that have has_many of some other model. Like a lot of ruby, it is deceptively simple! These relationships are much more complex than detailed above – especially when these relationships begin to grow in diversity. Remember: there are six supported associations, and these are only the first three! Not to mention polymorphic associations (oye! makes my head spin!). But also remember: Rome wasn't built in a day. All it takes, really, is patience, close readings of any and all documents available to us, experimentation and practice, practice, practice! Baby steps are hard when you're a baby! But those baby steps turn to walking fast, and eventually, we all get to run.
Top comments (0)