Chukwuma Anyadike
Posted on May 15, 2023
The nice thing about using Rails is that it allows us to use Active Record to create a database of organized information. With client-server communication the user can request data and have it returned and displayed in the browser. The user triggers an event (hitting a like button, submitting a form, and on and on). Information is requested and/or sent using a fetch request. This fetch request at the minimum includes an HTTP verb such as GET, POST, PATCH, and DELETE and a URL which includes a domain name and a path. If information is sent it is typically included in a configuration object which contains a method (the aforementioned HTTP verbs except for GET which is implicit when you are only fetching data), headers which is typically {"Content-Type": "application/json"} to send JSON data, and a body which contains data which is converted to JSON (JSON.stringify(consult)). Once the promise is fulfilled then JSON data is returned.
I will delve into how this JSON data is returned. Basically I will talk about the power of serialization. Ever since I discovered serializers, I feel powerful.
But in all seriousness using serializers is a great way to customize the way that data is displayed on the backend. I will briefly talk about how this is achieved and show examples from my own projects. Let us start by defining serialization. Data serialization is the process of converting/translating data into a format that can be shared (over a network) or stored (in a file, in memory or in a database) and then be converted back to its original structure.
For our purposes, serialization is taking our JSON output and formatting it in a desired fashion to facilitate the use of this data on the frontend (client).
First we need to setup our backend to allow us to use serializers. Serialization can be done in our controllers but it can get complicated and cumbersome very quickly, especially if the models contain a lot of attributes. Serializers allow separation of concerns which means that while the controllers communicate with our models to render data, serializers determine how that data is displayed. ActiveModel::Serializer (or AMS) provides an easy way to customize how the JSON rendered by our controllers is structured.
Since Ruby is about gems, guess what? We will install another gem. Let us install the gem for our serializer in our Gemfile.
# Gemfile
#...
gem 'active_model_serializers'
Now run bundle install
in your console. Next generate your serializer for your model by running the command rails g serializer your-model-name
. Let's assume our model name is 'model'. The serializer that was just generated will look like this. Here, we can list that attributes that we want displayed.
class ModelSerializer < ActiveModel::Serializer
attributes :id, :attribute1, :attribute2, ...
end
For many if not most cases this would be all you need. Think about it, you can decide which attributes you want displayed and which ones you want excluded. However, what if you just need more. With the use of our associations (has_many, belongs_to) and customized instance methods we can tap into the full power of serialization. It's kind of like being one with the force (if you are a fan of Star Wars) or tapping into the speed force (if you like the Flash).
Watch as I proceed to illustrate this with examples from my own projects. I will start with serializing associations. Let's begin with my Provider
model.
The schema
create_table "providers", force: :cascade do |t|
t.string "username"
t.string "password_digest"
t.string "first_name"
t.string "middle_name"
t.string "last_name"
t.string "type_of_provider"
t.string "department"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
The model
class Provider < ApplicationRecord
validates :username, :first_name, :last_name, :type_of_provider, :department, presence: true
validates :username, uniqueness: true
has_secure_password
has_many :appointments
has_many :patients, through: :appointments
end
Serializer
class ProviderSerializer < ActiveModel::Serializer
attributes :id, :username, :first_name, :middle_name, :last_name, :type_of_provider, :department
has_many :appointments
has_many :patients
end
JSON Output
{
"id": 3,
"username": "doctorstrange",
"first_name": "Stephen",
"middle_name": "Allen",
"last_name": "Strange",
"type_of_provider": "Physician",
"department": "Neurosurgery",
"patients": [
{
"id": 7,
"first_name": "Cletus",
"middle_name": "Ziemann",
"last_name": "Altenwerth",
"birth_date": "1961-02-19T00:00:00.000Z",
"sex": "M",
"image": "",
"address": "778 Vance Summit Jewellton, Arkansas 05528-0096",
"phone_number": "1-486-568-3938 x766",
"email_address": "roberto@wolf.test",
"insurance": "Aetna",
"age": 62,
"picture": null
},
{
"id": 9,
"first_name": "Kayce",
"middle_name": "MacGyver",
"last_name": "DuBuque",
"birth_date": "1988-06-30T00:00:00.000Z",
"sex": "F",
"image": "",
"address": "910 Ankunding Road East Jacquelynborough, Kentucky 95561",
"phone_number": "(346) 455-8971 x90000",
"email_address": "glendora@greenfelder.test",
"insurance": "Cigna",
"age": 34,
"picture": null
}
],
"appointments": [
{
"id": 18,
"provider_id": 3,
"patient_id": 7,
"type_of_appointment": "Inpatient: Surgery",
"location": "NYU Langone Brain and Spine Center",
"date": "2023-05-06T19:30:00.674Z"
},
{
"id": 19,
"provider_id": 3,
"patient_id": 9,
"type_of_appointment": "Outpatient: Consultation",
"location": "NYU Brain and Spine Center",
"date": "2023-05-06T19:12:48.112Z"
}
]
}
In the above example, I took a model called Provider
and used a serializer called ProviderSerializer
to customize the JSON output to display the attributes of Provider
as listed in the attribute section of the serializer as well as all patients and appointments for Dr. Strange using the known associations for this model.
Let's take note of a few things. Note that ProviderSerializer
inherits from ActiveModel::Serializer
. Furthermore the name of the serializer follows the typical Rails 'convention over configuration' in that the name is the model name (Singular!) and Serializer. Note that all attributes except the password digest
, created_at
, and updated_at
were included for display. The use of the has_many
macro allowed the display of all patients and appointments associated with Dr. Strange.
Let's kick this up a notch. Instead of returning all information on the patients and the appointments for this provider return an list of patients and appointment with just the basic information. We can use custom instance methods in our serializer to do this.
Serializer
class ProviderSerializer < ActiveModel::Serializer
attributes :id, :username, :first_name, :middle_name, :last_name, :type_of_provider, :department, :patient_list, :appointment_list
def patient_list
patients=self.object.patients
patients.map do |patient|
"#{patient.last_name}, #{patient.first_name} DOB: #{patient.birth_date.strftime("%m/%d/%Y")}"
end
end
def appointment_list
appointments=self.object.appointments
appointments.map do |appointment|
patient=Patient.find(appointment.patient_id)
"#{patient.last_name}, #{patient.first_name} || Type of appointment: #{appointment.type_of_appointment} || Location: #{appointment.location } || Date: #{appointment.date.strftime("%m/%d/%Y")}"
end
end
end
Note that I created two instance methods patient_list and appointment_list to return lists of the patients and appointments respectively in abbreviated form. Also note the use of self.object
to refer to self
(instance of Provider
) is similar to the way you would use self
in Ruby. Here is our JSON output below. Note how much nicer this looks, so sweet and so smooth.
JSON Output
{
"id": 3,
"username": "doctorstrange",
"first_name": "Stephen",
"middle_name": "Allen",
"last_name": "Strange",
"type_of_provider": "Physician",
"department": "Neurosurgery",
"patient_list": [
"Altenwerth, Cletus DOB: 02/19/1961",
"DuBuque, Kayce DOB: 06/30/1988"
],
"appointment_list": [
"Altenwerth, Cletus || Type of appointment: Inpatient: Surgery || Location: NYU Langone Brain and Spine Center || Date: 05/06/2023",
"DuBuque, Kayce || Type of appointment: Outpatient: Consultation || Location: NYU Brain and Spine Center || Date: 05/06/2023"
]
}
As one can see serializers are another tool in our Rails toolbox that we can use to enhance the richness of our applications. In this example a streamlined patient list and appointment list was generated for Dr. Strange entirely from the backend with no work on the front end. This can be done with any resource provided that certain conditions are met. Serialization can be taken to the next level using associations and custom methods. This is the power of Serialization. I'm out.
Posted on May 15, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.