In object oriented programming, an association is a relationship between objects, such that an instance of one class can cause an instance of another class to perform an action on its behalf.
There are six types of associations that fall into one of three categories:
Lets start with the first category, one-to-one. This association is between two models; let’s call them ‘owner’ and ‘belonging’. As one might expect, the belonging ‘belongs_to’ the owner. On the flip side, the owner can have one or more belongings, either directly or through another model. Here, we are concerned with a) the implications of an object belonging to another, b) the case where the owner has only one belonging, and c) the case where the owner has only one belonging, through a third model.
As mentioned above, the belonging belongs to the owner. This means that each instance of the belonging class (in this case Song) can have only one instance of the owner class (in this case Artist).
When new records of objects are created and stored into relational databases, ownership is represented through the use of foreign keys. A foreign key is just a column in the belonging’s database, where the id of the owner is stored. So an instance of owner is borne with an individual id, our belonging table will have an ‘owner_id’ column. When we create an instance of belonging that belongs to an instance of owner, we will store that owner’s individual id to the row where information about our instance of belonging is stored.
Remember: the belonging (or object that ‘belongs_to’) always holds the foreign key.
We mentioned above that in one-to-one relationships, the belonging object has one owner. What happens to the other side? The has_one association is used whenever the owner has one belonging only. Say that the purpose of our app was to create a playlist that features various artists. Our playlist can include only one song by each artist. Our association will look like:
We could store the data as follows:
In our simple example one might ask, why have an Artist class at all? We could accomplish the same with the following:
The answer is if we wanted to adhere to the principle of separation of concerns. We might to structure out database so that all information pertinent to each object is contained within that object. Let’s look at another example where a user has one account and an account belongs to a user. It would be best to separate information and actions pertinent to the user, from those relevant to the user’s account. We could create and store the data as follows:
The ‘owner’ has one ‘belonging’ through a third class. I struggled to find examples that would adequately demonstrate the practical usefulness of this association. But let’s say an employee has one job, the job has one location. Then the employee would have one location through job. I guess, same as above, one would use it when she wants to separate concerns and add attributes to each model.
This is one of the options that go on the other side of a belongs_to association. Lets revisit our playlist example. We said that each song belongs to one artist. If we did not want to impose any restrictions on the number of songs by each artists (as we did to demonstrate the has_one association), then an artist can have many songs. This is a one to many relationship and the structure is belongs_to/has_many.
There are two ways to set up a many to many relationship. The first is using a third model through which the association is made. For example, say we want to associate actresses and films so that an actress has (or appears in) many films and a film has many actresses (many actresses appear in it). We can have a third model named Appearance that will belong to both the actress and film models and thus will hold both foreign keys (actress_id, film_id). Though Appearance, we can keep track of the films that an instance of Actress has appeared in as well as all the instances of actress that appear in an instance of Film. Our associations will look like:
Our data tables could look like:
This is the second way to set a many to many relationship. Similarly to the previous association, we need a join table that will hold the foreign keys. The difference is that we don’t need a third model. The association is made directly. We just need to declare our associations and create the join table (we can name it actresses_films) that contains the foreign keys only (no individual id). Our table would look like:
Ok. So both methods accomplish the same thing — associating the two models — then why use one vs. the other?
We should use has_many_through when we want our relationship to be ‘a separate thing’. That is when we want to create instances that may have attributes or validations. This should be in most cases in practice. In any case, why would we want to limit ourselves from the outset? The has_and_belongs_to_many setup may be simpler and faster, but it is more restrictive. In our example, since there is no third model we cannot add any attributes to the relationship such as rating or appearance date for example, or any validations.