A lot of material has been introduced since I last wrote a post on day 9. My cohort and I are currently knee deep in Object Oriented Ruby. This week I hit my first wall and am still struggling to completely wrap my head around the concept of object relationships. I think my main frustration is that I feel it is hard to visualize exactly what is going on as more objects have relationships with one another. One of the tougher topics to fully grasp and understand for me has been the has-many-through relationship.
The has-many-through relationship in Ruby is pretty simple to conceptually understand. In this example we will be using a relationship that may be used in the medical field. We have an appointment, a doctor and a patient. A patient may have many different doctors throughout their life, and the doctor is likely to have thousands of patients. What connects a patient to a doctor? The appointment. Typically, this is the only way the two meet, know about one another or have any sort of relationship.
Let’s start by taking a look at our appointment, doctor and patient classes. You will notice that the appointment class keeps track of every appointment created, and stores them in a class variable, which is of type array. Our patient and doctor classes have instance methods. Every new doctor and/or patient is able to create an appointment.
Creating an appointment with the class constructor and an instance method
If we were to create a new appointment using the class constructor, we must provide three things: a date, a patient and a doctor. You can see on line 4 that when we initialize a new appointment object, it expects to receive arguments that contain a date, a patient and a doctor. We can create a new appointment and store it in a variable called my_appointment by doing:
my_appointment = Appointment.new("Nov 15th", "Alexandra", "Dr. Mead"). However, this is not really helpful to us at all. The patient and doctor attributes won’t refer to an instance of a doctor or patient. The patient and doctor taken in by our appointment will just refer to a string object, which happens to contain their names. For this to be useful, we should store actual objects as the patient and doctor. This will allow for a doctor or patient object to lookup specific appointments that belong to them.
We can also use an instance method in the person or doctor class to create an appointment. If we have a doctor object stored in a variable called dr_johnson, we could create a new appointment by calling the relevant instance method and providing the required arguments to create a new appointment. Let’s say alexandra is a “real” patient (patient object, not just the string of her name). And we also have a doctor object stored in dr_johnson.
alexandra = Patient.new("Alexandra")
dr_johnson = Doctor.new("Dr. johnson")
We would create a new appointment using a doctor instance like this:
dr_johnson.new_appointment(alexandra, "Nov 15th")
How is the appointment receiving our doctor instance if we are only passing the patient and a date to our instance method? Pay close attention to line 11 of the doctor class. Within this instance method we are also passing self, although our method does not take it in as an argument. In the scope of our instance method self will be our doctor instance (dr_johnson).
Functional Example and Output
To show everything in action and for clarity’s sake, I have put all of the classes in one file and added some doctors and patient objects.
First we will use the appointment constructor to make a new appointment instance. We will create a new doctor and patient instance, and pass those two object in when we create the appointment. The next two examples use a doctor and patient object to create appointments using their respective instance methods. When we inspect our appointments using
Appointment.all, we will see that our appointment attributes for doctor and patient actually point to those objects.
Notice the same doctor object was used to create an appointment using both the appointment constructor and patient instance method. You can tell it is the same object, and not a new object with the same name, because it has the same address in memory (0x007fd92022b478).
Now that every appointment we create records the doctor and patient object in an attribute, we can select all appointments where we were the patient and store that in a list. In a patient instance method, perhaps we could iterate over all appointments, compare each appointment’s patient to self, and if it matches we store that in a new array. We could then use our new array, which contains all appointments for which we were the patient and then output all of our doctors. The reverse would also work for a doctor trying to obtain a list of appointments where he/she was the doctor. No doctor or patient has a direct relationship to the other without going through an appointment.
I hope this helps someone out there that is struggling with trying to see the benefit or point of a has-many-through relationship.