Last week, I covered tricks and tips with handling forms and updating state, as well as sending the data through fetch requests to the backend. Since then, I have been working endlessly on fetching data from the backend, which included building relationships between my various models and sending the data through a Json Serializer made by Netflix, Fast_JSONAPI Serializer (now just JSONAPI Serializer). I learned some new things while working with the serializer and felt I could impart my wisdom this week.
My application’s database is made up of multiple tables/models that are all connected through belongs_to and has_many relationships. Employees have profiles and previous work experience, and employers have job postings, which are all connected through their job applications. On previous projects, I would make too many fetch requests to acquire necessary data, for example one request for an employer and another for associated applicants. I was slowly realizing that if an employer had a lot of job postings or applicants, the data might take a long time to load.
I had some experience building serializers in the past, which helped define the data in a readable json format. This included iterating through associated data in an attempt to minimize fetch requests. The reducer would receive the results and I would iterate through the nested data to correctly update the state.
class RecordSerializer
include FastJsonapi::ObjectSerializer
attributes :id, :date, :daily_allowance, :daily_total, :user_id
has_many :days
attribute :days do |record|
days = Day.where(record_id: record.id)
recs = {}
days.each do |day|
recs[:id] = day.id
recs[:item_name] = day.item_name
recs[:item_calories] = day.item_calories
end
end
end
It worked fine in the past, but I knew there had to be a more efficient way to deliver the data without it being so nested in the results. Upon reading the instructions for JSONAPI, I found that it wasn’t necessary to define an iterator. By setting up a serializer similar to a model with belongs_to and has_many attributes, I could simply include the profiles and work history when an employee is initially fetched.
class EmployeeSerializer
include JSONAPI::ObjectSerializer
attributes :id, :email, :name
has_one :profile
has_many :work_histories, through: :profile
has_many :applicants
has_many :jobs, through: :applicants
end
render json: EmployeeSerializer.new(@employees, include: [:profile, :work_histories])
Things started to become a little bit clearer, until I started attempting to pull large sets of data that were connected to jobs. When an Employer signs in, I envisioned jobs data associated with the employer would be delivered as well. Then I expanded to include potential candidates (connected through applicants join-table) which also included the profile information and previous work experience. My reducer was becoming larger and filled with too much code, and I could visually see the long logs to fetch the jobs.
I went back to the read me portion of JSONAPI and learned that there was an alternate way to deliver associated records.
class JobSerializer
include JSONAPI::ObjectSerializer
belongs_to :employer
has_many :applicants
has_many :employees, through: :applicants
has_many :profiles, through: :employees
attributes :id, :employer_id, :status, :title, :city, :state, :jobtype, :schedule,
:skills, :certificates, :description, :employees, :profiles
end
Since both employees and their profiles are already related to jobs, they can be inserted as attributes for JobSerializer. This will deliver all associated employee information already defined in the EmployeeSerializer, along with profiles defined in the ProfileSerializer. With a single fetch request, I have all the necessary data to display an employer’s jobs postings and potential candidates information, rather than fetching employees later on. Originally, I was defining the parameter through object_method_name, but I realized (stumbled upon) that it was only necessary if I wanted to assign the parameter a name different from its given name.
I might have spent a little too much time refactoring my code instead of building on features for my application, but my code is much cleaner and works very well to boot. The real test will be when I have copious amounts of records in my database and how long it takes to load it all on this single fetch request. I’m also attempting to learn how to define related links in the Serializer that JSONAPI says would be helpful in gathering data in later requests. I will attempt it and see how well it turns out. Until next time!
Top comments (0)