Ruby on Rails - Cookies and Session



The Ruby on Rails framework follows the MVC pattern that implements REST architecture. One of the important constraints of REST is statelessness. It implies that each request sent by the client must have enough information for the server to handle and satisfy it, and that the server doesn’t hold on to the request data once it forms the response and disconnects from the client.

What are Cookies?

In some situations web applications need to maintain state between multiple requests. When a user successfully logs in, they shouldn't be asked to log in again when accessing another resource. Rails (in general the applications implementing REST) uses cookies to store data between multiple requests.

Cookies are small pieces of data stored in the user's browser. Rails allows you to set, read, and delete cookies. The cookies method in Rails acts as a hash.

To set a cookie

cookies[:username] = { value: "Test User", expires: 1.hour.from_now }

To return the cookie value

cookies[:username]

in this case Test User.

To delete a cookie, use the following expression:

cookies.delete(:username)

What are Sessions?

Sessions are a wrapper over cookies. Rails encrypts and signs to store more sensitive user-related data securely. Rails stores session data in a cookie by default using ActionDispatch::Session::CookieStore.

Setting session data

session[:user_id] = @user.id

Reading session data

User.find(session[:user_id]) if session[:user_id]

Deleting session data

session.delete(:user_id)

Flash Messages

Flash messages in Rails are built on top of the session object. They are used to pass temporary one-time messages (like success or error alerts) from one request to the next.

Rails provides a flash hash that's stored in the session. Flash uses the session behind the scenes −

  • It stores the flash hash in session['flash'].
  • On the next request, Rails clears the flash data automatically (unless told otherwise).

You can render the following types of flash messages −

Flash Key Purpose Display Color
:notice For general success messages Green or Blue
:alert For warnings or errors Red
:error Custom — often for errors Red
:success Custom — for clear success Green

Examples

flash[:notice] = "Successfully logged in"
flash[:alert] = "Invalid username or password"
flash[:error] = "Something went wrong!"
flash[:success] = "Your profile has been updated"

Example: Cookies, Sessions, and Flash Messages

Let us put the concept of cookies, session and flash in the following example.

Start by creating a new Rails application

rails new sessiondemo 
cd sessiondemo

Add a User model and corresponding controller and views by generating the scaffold.

rails generate scaffold User name:string email:string password:string
rails db:migrate

You need to create a Sessions Controller for handling Login/Logout operations

rails generate controller Sessions new create destroy

Add the login and logout routes by editing the routes.rb file in the app/config folder.

resources :users
get 'login', to: 'sessions#new'
post 'login', to: 'sessions#create'
delete 'logout', to: 'sessions#destroy'
root "users#index"

The SessionController class defines the methods for performing Session activities. The new action sets up a cookie as the email of logged user.

When a user logs in, a new session is created. It also flashes a message letting the user know that the login is successful. The destroy action removes the session variable.

In app/controllers/sessions_controller.rb

class SessionsController < ApplicationController
	def new
		@remembered_email = cookies[:remembered_email]
	end

	def create
		user = User.find_by(email: params[:email])

		if user && user.password == params[:password]
			session[:user_id] = user.id
			flash[:notice] = "Welcome, #{user.name}!"

			if params[:remember_me] == "1"
				cookies[:remembered_email] = { value: user.email, expires: 1.week.from_now }
			else
				cookies.delete(:remembered_email)
			end

			redirect_to user_path(user)
		else
			flash.now[:alert] = "Invalid email or password"
			render :new
		end
	end

	def destroy
		session.delete(:user_id)
		flash[:notice] = "You have been logged out."
		redirect_to login_path
	end
end

Add Helper Methods to ApplicationController

class ApplicationController < ActionController::Base
	helper_method :current_user, :logged_in?

	def current_user
		@current_user ||= User.find_by(id: session[:user_id])
	end

	def logged_in?
		current_user.present?
	end
end

Create Login Form View

Rails automatically creates the view for the new action.

Edit the app/views/sessions/new.html.erb as follows −

<h1>Login</h1>

<%= form_with url: login_path, method: :post do %>
   <div>
      <%= label_tag :email %><br>
      <%= text_field_tag :email, @remembered_email %>
   </div>

   <div>
      <%= label_tag :password %><br>
      <%= password_field_tag :password %>
   </div>

   <div>
      <%= check_box_tag :remember_me, "1" %>
      <%= label_tag :remember_me, "Remember me" %>
   </div>

   <%= submit_tag "Login" %>
<% end %>

The Flash Messages are added to the Application Layout.

Open the app/views/layouts/application.html.erb file to add a logout button when a user is logged in.

<body>
   <% if flash[:notice] %>
      <p style="color: green;"><%= flash[:notice] %></p>
   <% end %>

   <% if flash[:alert] %>
      <p style="color: red;"><%= flash[:alert] %></p>
   <% end %>

   <% if session[:user_id] %>
      <p>Logged in as <%= User.find(session[:user_id]).name %> |
      <%= button_to "Logout", logout_path, method: :delete, data: 
        { confirm: "Are you sure you want to log out?" } %></p>
   <% else %>
   <%= link_to "Login", login_path %>
   <% end %>
   <%= yield %>
</body>

You can now test the functionality by starting the Rails server and visiting the /users route to create a new user.

Rails Cookies and Session1

Go to /login and log in.

Rails Cookies and Session2

Check the "Remember me" box and reload the page later to see your email remembered.

Rails Cookies and Session3

Log out to test session and flash behavior.

Rails Cookies and Session4
Advertisements