The cookie sessions

Serena Bright
6 min readAug 7, 2019

--

HTTP is a stateless protocol. Sessions make it stateful. (Rails Docs)

What's a cookie?
What's the data flow problem cookies solve?
How to find all the cookies on a page?
What's a session, as far as Rails is concerned?
Where is session data stored?

What does this mean to a coder?

When we had the flash and key of errors, why did we have to differentiate between create and update where one is set up with render and another one with redirect? What is good for one request, the contents of the flash?

Let’s explore an example of a shopping cart.

I have the list of items that I need to be added to my shopping cart. I need those to stay in the shopping cart. What do we use for storing that data? If I click on the “buy”, or “add to shopping cart” button next to the item on the online store page, I need this action to last more than one single request. My shopping cart needs to be in the format of an array to store my items. When I go back there, I should be able to see all the items I have added.

Stateless protocol means that one request does not know about the previous request. HTTP server receives requests, processes them, returns data, then forgets about them. If were to go to the new page, do I still have access to the array of items? No, because it is a different controller action, it’s a different method. In my show page, I do not have access to this array, because of Ruby’s scope. From one RESTular request to another, the state’s data is not transferred from one to another.

In terms of the web requests. Inside the headers, a lot of the information gets passed, sent back and forth. If you open your Chrome console, in Application, there will be a cookie (found in Storage), with the http//localhost:3000 with a hash of name and value. Each domain tracks its own cookies. You can’t read and understand the value in these cookies. Does it make sense to make it readable? Of course not, it’s not safe! The information that is passed back and forth can keep track of you.

Cookies are a way for an HTTP server to ask the user’s browser to store some of its data for it, and then to retrieve that data back from the browser later. Cookies also play the main role in making sure you remain logged in to your account for as long as you need so that you don’t have to re-sign in each time you refresh a browser.

What if I go ahead and delete the cookie, what will happen? My array will get deleted. But also, the server will create more cookies if there is nothing there. One cookie’s name is called sess-session. With this session, will Ruby be able to track the user and user data? This cookie is actually tracking the data.

If the session is stored inside this cookie, I can get access to the data that goes back and forth.

So, how do I create the shopping cart?

If I click on that button, I need to set it up to go to the cart route. The item is going to go to the URL that I specify. The hash will need to get added to that array.

I check my index page.

I go to my routes.

I want to be able to name things properly.

Adding something to a cart. I am not actually creating a new cart — I am updating, hence, I use method: PATCH. In routes, I add an action patch ‘/cart’, to: carts controller and I want the update method. Now I make the Rails g controller carts. Inside the carts controller, we want to hit the update method. I want to test if I can even hit the controller action. If I can’t, I will find out why. Now I want to check params, to see what comes through, what is useful. What would be very useful? Any information. If I hit a button, I want item’s id to show up. Inside my index, I do :patch, params: {item_id: item:id}

Now I want to let the user know they did something. I use a flash message

def update
@item = Item.find(params[:item_id])
flash[:notice] = “you’ve just added this #{item.name} to the cart”
session[:cart] = []
session[:cart] << @item.id
redirect_to : items_path
end

I should also add the notice to the index!

Now I refresh and lose all data on the webpage that was just showing me my results. This is why we need a session. We add a session to our code block. Session is extremely large and holds a huge amount of data, so session is a key-value pair. Inside the cookies, there can only be stored stings. In the beginning, the session’s value is nil. You can’t push it in nil. But you can push it in an empty array.

We want to be able to create something that determines that this key or cart exists and if it does, I want the cart back. If it doesn’t, I want to create a new cart. Who should have access to the cart, only the item controller? How can we create methods or object that every single controller can possibly have access to? Application controller. I want a method that is going to hold my cart. I want to name it cart. Inside this cart, I want to see

def cart 
if session[:cart] == nil
session[:cart] = []
else
session[:cart]
end
end

Alternatively, refactoring:

def cart
session[:cart] ||= []
end

||= means or equals

If it’s nil, then create an array, otherwise, assign it to the existing array.

Now I want to add something to this cart.

def add_to_cart(item_id)
cart << item
end

Since I have access to the application controller, because my cart controller inherits from it, I can simply invoke that add_to_card function in it.

I still need to display the cart into the view

def show_the_cart
@cart_items = Item.find(cart)
end

We put everything about sessions (methods, etc) in the ApplicationController, and not in the other controllers. But other controllers can use those sessions methods.

A few more steps — still need to show what is where, and my cart’s entries persist. I hit refresh and I see my cart and the items in it.

Session and flash. One lasts for one request and another one persists (session).

Session and passing the params in the button were the two things that are the key points in this blog.

We have access to the session hash that I can use to persist data from request to request. And then we built out a feature to boost confidence. If I don’t know how to build a feature, at least I know how to start, and it’s with the routes. If the route is good, it points to the controller action: which controller action I want to point out to and why. All of the data is encrypted in cookies. Cookies are domain-specific. If I switch to the incognito window, I get all new cookies.

So, what’s the difference between cookies and sessions? It’s about where/how they are stored. Both are used to store information. Cookies are only stored on the client-side, and sessions get stored on both the client and a server. Session locks data in the locked box and the server controls that box, no one can change that. If they try, the server will throw that out and generate a new cookie.

Flash only persists for one request-response cycle. https://www.tutorialspoint.com/What-is-the-difference-between-session-and-cookies

The content of that box maintains the format of that box. If my data type is an integer, it will be stored as an integer.

my_pass = BCrypt::Password.create(“abc123”)
my_pass.class => BCrypt::Password
my_pass.salt => “jfhfgfhjddssshs”
my_pass.checksum => “heggddgsgayausu”

Our database can only store strings. It cannot store BCrypt Passwords.

stringy == the value of the password hash. It’s not a string though. It does not equal to the string of the same combination of letters. To turn stringy into a string, we do:

BCrypt::Password.new(stringy)

Migration tip: if I have to change my schema on a collaborative project, I should change it in the master. Then, when I go to my branch and pull it (git pull origin master), I will get the latest migration. But! My schema will remain old. I would still need to db:rollback and remigrate it.

That’s it for the tricks on cookies and sessions. I hope it was helpful!

Happy coding.

--

--

Serena Bright

Product Manager and Sustainability Professional building a climate startup