Cookie Limit
Tags: ruby, webdev, programming
Published: 2023-08-05 16:56:54

## Intro

I've been working on a [mini project](https://titos-and-vodka.fly.dev/) using Sinatra. I'm attempting to use everything I've learned in Ruby.

I'm constantly trying to find new things to add to make sure I cover all the bases I have learned so far. Currently I am working on creating an advanced search section in which users can add whatever ingredients they have and they will receive an array of cocktails they can make with those ingredients.

In order to keep data upon each render. I am storing the data as cookies. As a React Developer, I would've just used state, so I am finding this problem very helpful.

## Attempt

Upon calling the API with a query of a certain ingredient the API returns all the cocktails that contain those ingredients in JSON. My initial idea was to have the current drinks array and modify it after a new ingredient is added:

```ruby
new_ingredient = params.fetch("new_ingredient")

ingredient_list = JSON.parse(cookies["ingredient_list"])
ingredient_list.push("new_ingredient")

new_cocktails_req = HTTP.get("API including #{new_ingredient} param")

new_cocktails_res = JSON.parse(new_cocktails_req).dig("drinks",0)

current_cocktails = JSON.parse(cookies["current_cocktails"]) #The cookie is initialized in the get route

filtered_array = []
if current_cocktails != []
  current_cocktails.each{|cocktail|
    if new_cocktails_res.include?(cocktail)
      filtered_array.push(cocktail)
    end
  }
else
  filtered_array = new_cocktails_res
end

cookies["ingredient_list"] = JSON.generate(ingredient_list)

cookies["current_cocktails"] = JSON.generate(filtered_array)
```

## Problem with this code

I was noticing that the ingredient_list was being stored in local storage; however, the filtered_array was not. I was able to display the filtered_array using irb to see if it was working as it should and it was. So I figured that it had to do with cookie storing. I modified my code and nothing changed, so I figured there must be a limit. **There is a limit.** The limit is **4096 bytes**. Each character counts as a byte, so str.length returns the number of bytes the string contains.

I converted my filtered_array to JSON and checked the length. It was **14,036 bytes** exceeding the limit. If the cookie that is being stored is greater that 4096 bytes. The cookie is not modified.

## Solution

I could easily store the filtered_array in local storage but there are two problems with that:

1. Storing a string in local storage is an synchronous process so the main thread will be blocked. Compared to cookie storing which is async.
2. Although I'm familiar with local storage, it is something I haven't covered in Ruby yet.

My current solution revolves around storing the cocktail IDs as opposed to the entire cocktail hash and at the point of render fetch each cocktail in the list. At first, the list will be very long but as more ingredients are added the list should decrease following an exponential decay graph to 1 or 0.

## Issue with my solution

Let's say my array of ids is of length 1000 and each id is of length 5. That will exceed the local storage size. Luckily, that shouldn't happen since the cocktail database I am using isn't that large.

The next issue will be if I have the array of ids of length 50 which is very plausible. I will have to make 50 calls to the API in the get route using a for loop. Can the API even handle that in time to render the page? If it can't are promises even a concept available in Ruby?

## Update: August 5, 2023

I attempted to declare a global variable to store the array of cocktails in my app.rb file. Unfortunately, the blocks within my routes do not have access to global variables.

After further consideration, I realized since storing in local storage is a synchronous process. The webpage will wait til the process is complete to render. This should allow the page to:

1. Store a larger array
2. If I kept an array of IDs, I would be able to create and resolve a request for every single ID.

Luckily, the second option is not necessary since local storage can store a larger array than cookies.

I will incorporate this update when I cover local storage in Sinatra.

## Final Update: August 22, 2023

When reviewing Ruby Classes and Objects. I went deep into a variable rabbit hole. Luckily this lead me to figure out how to declare a global variable in Ruby within a method block. Even though this was a solution I had in mind since my last update. I am glad I got it running.