"Dessert" and How To "Eat" It
Tags: beginners, codenewbie, webdev, rails
Published: 2022-02-22 08:28:18

Today, we're talking cookies. Something something, joke about tasty baked goods... No. Even if you don't have much experience with programming, you likely have heard about cookies, if only because websites keep asking if they can use them. Even if you've already heard about them, it's good to have a proper understanding of what they do. Cookies are used by websites to store information on the user's side of the website experience. This allows the website to do things like; keep you logged in on return visits, remember your password, track what you're viewing, etc.  Since HTTP (the go to language for websites) doesn't have a way of keeping track of any of this information by itself, cookies lets it hold onto all this information and more for use in the web browsing experience.

# Baking the Cookie

I know I said no to the baking joke earlier, but I had to. Now that a basic understanding is established, we're going to be getting into the more technical side of things. For this blog post, I'll be using **Ruby on Rails** and **React**, although Rails will be the focus, but if you're going to be following along with me in an actual app, you'll need to do some things first. In order for a fresh Rails application to use cookies, you will need to go into `config/application.rb`. Once there, you'll need to remove `config.api_only = true` and replace it with the following:
```
config.middleware.use ActionDispatch::Cookies
config.middleware.use ActionDispatch::Session::CookieStore
```
You'll also want to add in `config.action_dispatch.cookies_same_site_protection = :strict` for security.

Now that the basic setup is done, we'll move onto properly utilizing cookies.

# Authentication

One of the main uses for cookies is logins, so lets cover it. When you first visit a site, you log into it. Makes sense, but it would really suck if every time you leave the page, or even reload it, you'd have to re-sign in. That's where authentication comes in. Once you've logged in, the site remembers who you are, so that when it sees you again, it doesn't have to ask. Now all the annoyances of logging in over and over are gone, but how do we do that?

Let's start out really easy. We'll create a path we can post to for logging in.
```
post "/login", to: "sessions#create"
```
Looks great, but the place we're posting to, `"sessions#create"`, doesn't actually exist yet. So let's make it and walkthrough what it means. (# indicates that the line is a comment)

```
# lets setup the thing in charge of session as a whole first

class SessionsController < ApplicationController

  # now onto the create part of "sessions#create"
  # this is the thing that directly handles making new users
  def create

    # now we'll establish the user that is currently logging in,
    # set that as the current user this session, and send that 
    # info back to the frontend.
    user = User.find_by(username: params[:username])
    session[:user_id] = user.id
    render json: user
  end
end 
```

That's our backend all sorted. Now our front end just needs to send a POST fetch request to "/login" with our username and we're good to go... except not quite. While this does log us in and our backend will remember us when we come back, our frontend won't. This is because our frontend and backend don't have a way of telling each that information. Let's fix that.

Just like before, we'll add in a new path that our frontend can fetch to.
```
get "/me", to: "users#show"
```
Since we're getting info instead of sending info, we use `get` this time instead of `post`. Now we set up our User Controller to handle `"users#show"`.
```
class UsersController < ApplicationController
  def show
    # same as before we establish the current user
    user = User.find_by(id: session[:user_id])

    # but this time we check whether user exists
    # if it does we send that, if not we send an error
    if user
      render json: user
    else
      render json: { error: "Not authorized" }, status: :unauthorized
    end
  end
end 
```

Now that our backend is set up, we'll add in the following to our frontend so that it can get all that info;
```
useEffect(() => {
    fetch("/me").then((response) => {
      if (response.ok) {
        response.json().then((user) => setUser(user));
      }
    });
  }, []);
```

With our application now able to remember us, we can finally do things with it... Like restrict people from doing certain things.

# Authorization

Time to make a VIP room! Now that our cookies established who everyone is, we can have it where only certain people are authorized to do certain things. Authorization can be used to give special features to premium members, enable admin powers, or in our case, make a VIP page that only some people can view.

Rails has a lovely beautiful tool called `before_action` that allows us to filter out who can do or view whatever we choose. So in our case, if we only want authorized people to be able to "enter" our VIP room, we simply put `before_action :authorize` before our VIP code. Now what if we wanted everyone to see a little bit of how much they were missing out? We can simply add `skip_before_action :authorize, only: [:preview]`.


While this is just the tip of the iceberg, I hope that I've helped you understand the power of cookies and just how delicious dessert is.