I like to think of associations as relationships. How is this model related to that model? If they met each other on the street, and their friend was there, how would they describe their relationship? The most common relationships are belongs_to, has_many, has_many, through:, and has_one. What do those even mean? I find the best way to understand relationships is through an example.
Right now, I’m working on a project for screenwriters. The purpose of the project is to allow the screenwriter to enter their project and to track query letters sent to agents. So first, I start with my models. I know I’ll need a user, but in this case, I’ll call that a screenwriter. Next, I want to make a screenplay model. That screenplay should have at least one genre, so I’ll create a genre model. Last, I’ll create an agent model.
Each of these models will have attributes, but I’m going to put that on hold for right now. Now, we want to determine what the associations are. We’ll tackle the easy ones first. A screenwriter doesn’t want to have just one screenplay. They want to make a career out of it, so we know that a screenwriter has_many screenplays, or at least the potential to have many screenplays. But a screenplay belongs_to a screenwriter. (Now, of course, a screenplay can have more than one screenwriter, but in this case, we’re going to consider a writing team as one unit.) A screenplay has_many genres, in the case of something that’s a drama and a comedy, or a romance and a comedy. A genre has_many: screenplays, since one screenplay can’t just declare itself the owner of the action-adventure genre. And last, the screenplay has_one: agent. So these are the basic relationships, but we have to go a little deeper.
If a screenplay has a genre, and a screenplay belongs to a screenwriter, then there’s another relationship we have to add, right? Right. A screenwriter has_many: genres, through: :screenplay. See how that works? I’ve found that it can be very helpful to map this out on paper or using google draw or a similar tool. You start to naturally see the flow of information. So, if that’s the case, what else do we need to connect here? A genre has_many screenwriters, through: :screenplays. An agent does have_many genres, through: :screenplays as well, but I don’t see that association necessarily being useful for what we’re trying to accomplish unless we want to sort the screenplay genres that belong to an agent to see if there’s a particular genre the agent represents. The interesting thing about associations is that they aren’t always straight forward. You have to think about the practicality of the situation, and what works for the user.
I want to point out that we have a natural join table here. This is where the two people meet and sit down so they can talk to each other. Our screenwriters have an association with an agent through a screenplay (screenwriter has_one agent, through: :screenplay; agent has_many screenwriters, through: :screenplays). The agent and the screenwriter meet at the screenplay table. So this is where they are joined together. This means that the screenplay table needs to have ids for both of these models on the table.
It won’t always be really clear what the associations are, and that’s ok. Take some time to map out some of the relationships until you get a feel for it. At the beginning of my Rails project, I had a hard time imagining what the relationships looked like, but by the end of the project I couldn’t understand what I didn’t understand about it. The more you do it, the more natural it becomes.