Making jQueries

Posted by remclay on June 6, 2018

My most recent portfolio project involved adding a jQuery front-end to my existing Rails app.

There were some real ups and downs during this project. It wasn’t necessarily that I struggled to get things working, rather that I didn’t do them the most efficient way the first time around.

The upside of this is that I learnt a lot during this project - as much about persevering through times of slow (read no) progress as about ajax and jQuery in general.

A real breakthrough moment was when I was introduced to the possibility of having my serializer provide the return value of a method on my model, in addition to providing serialized model attributes.

Prior to implementing this, I was relying on my ActiveRecord associations and using a different serializer for each associated class.

It looked something like this:

class ListItemSerializer < ActiveModel::Serializer
  attributes :id, :list_id, :dish_id
  belongs_to :dish, serializer: ListItemDishSerializer
end
class ListItemDishSerializer < ActiveModel::Serializer
  attributes :name
  belongs_to :restaurant, serializer: ListItemRestaurantSerializer
end
class ListItemRestaurantSerializer < ActiveModel::Serializer
  attributes :name, :location
  has_many :dishes
end

(NB: I was using specific ListItem serializers over my existing DishSerializer and RestaurantSerializer to avoid grabbing attributes I didn’t need for this particular request).

My RESPONSE, was a monstrosity with the following structure:

{data: Array(7), included: Array(29), jsonapi: {…}}

The “data” array contained the seven list_items I expected to see. The “included” array contained the associated dish names, restaurant names and locations, incredibly nested, mixed in with one another, along with some additional data I didn’t want or need.

Now, I could have fixed whatever bugs existed, iterated over the arrays and ‘zipped’ the relevant attributes back together. Sure. But at this point I knew there had to be a better way.

Queue revelation. Define some additional methods on the model, and tell the serializer to serialize the return value of those methods, along with the object’s attributes.

I wrote three new methods in my ListItem class, that simply expose the list_items dish name, restaurant name and restaurant location.

I deleted the unnecessary ListItemDishSerializer and ListItemRestaurantSerializer and modified my ListItemSerializer as follows:

class ListItemSerializer < ActiveModel::Serializer
  attributes :id, :list_id, :dish_id, :dish_name, :restaurant_name, :restaurant_location
end

The response was significantly more manageable.

{data: Array(8), jsonapi: {…}}

Most importantly, the list_item and it’s associated attributes were grouped together as one object in the “data” array, eliminating the potential for errors associated with ‘stitching’ the response together.

attributes: {list-id: 6, dish-id: 6, dish-name: "Mac & Cheese", restaurant-name: "W&C", restaurant-location: "Denver"}
id: "23"
type: "list-items"

While I love the red, green, refactor mantra, I’ll be wary of doing a little more research next time, before spending too long implementing a process that feels like there ‘must be a better way’.

https://github.com/remclay/dish-list