Back to Blog

An Epic Adventure: How to Create Sessions in Rails

Posted by Flatiron School on August 6, 2015

This blog is part of a continuous series that highlights experiences, insights, and tutorials from learning developers at Flatiron in Web and iOS.

This may not be the most interesting of all stories, but it's one that needs to be told. That begs to be heard. And here I am, giving this story its very own particular voice (and thick-framed glasses!). So let's start at the beginning (alas, where most programming stories tend to start), and see if we can't make it through to the other side. Won't you, my dear reader, come on this jaunt with me?

Blog post image: dragon.jpg

We commence our journey in the darkest of crevices, a most important file hidden deep inside the config directory: route.rb. Here we need to establish a root directory, and hatch our grandiose session plans.

root 'posts#index'

resources :sessions, only: [:create, :new, :destroy]
get '/signup', to: 'users#new'
get '/logout', to: 'sessions#destroy'
get '/login', to: 'sessions#new'

We use the resources key word to add seven routes to our web application and quickly narrow these routes down to just the ones we need via the syntax ‘:only’. To keep things clear, for both us and our user, we will name these routes as ‘signup’, ‘logout’, and ‘login’ respectively. We do not play with metaphors here. Literal is best. Now, we have a sessions directory, and we can begin building our sessions conroller. To do this, we type the following into our terminal:

rails g controller sessions

This will give us a controller, and while we're here, let's fill out the actions to match our routes:

def new
end

def create
end

def destroy
end

Here we go!

Blog post image: at__here_we_go__by_blistinaorgin-d6qf87y.png

In order for our sessions hash to function, we need our user to be validated on the home page before visiting any other views. Thus ensues the process of validating and logging in a user. Yet, it is a bit more complicated than that for us programmatically. This involves creating a method we can access from any view on our website. For this we need to go to that forbidden place, we have yet to explore. The application controller.

class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_action :login_required

#This method checks if we have a user signed in
def login_required
if !logged_in?
redirect_to login_path, :notice => “Log in to edit or delete your post”
end
end

def logged_in?
!!current_user
end

helper_method :logged_in?

#This method gives us details about our user
def current_user
if session[:user_id]
@current_user = User.find(session[:user_id])
@current_user
else
false
end
end

helper_method :current_user

end

These two helper methods, current_user and logged_in? will allow us to access data pertaining to our user, regardless of the variables passed in through our controllers. We will be able to access them from anywhere in our views! And do notice the macro 'before_action :login_required,' — this makes it mandatory for a user to be logged in before access. But please, let's not get ahead of ourselves. Before we get to our views, we need to make a pit stop at our post controller to make sure it has access to all the necessary information. Most notably, that we allow a user to visit our home page, or more specifically, posts#index:

class PostsController < ApplicationController
skip_before_action :login_required, :only => [:index]

This macro does exactly what is says it does (dontcha just love rails?) — it allows only the index page of our posts controller to be visible to a user without first logging in (hence the skip_before_action — get it?!).

So now, finally, we are ready to enter the holy view!!!!

Blog post image: HolyGrail051.jpg

Now one might think, we should go to our post index page. However, that individual would be WRONG. Because we, programmers, are planners. And we want our user to be able to logout no matter what page they are on. I mean, really, sessions wants to be AVAILABLE, people!!! This means that not only are we going to go into that cute little layouts directory, but also we will be rendering a header from the application.html.erb file.

Rendering a partial is super easy, you simply do this within the body of your application.html.erb.

<%= render 'layouts/header' %>

Followed by the creation of “_header.html.erb” Now, we are embarking on the climax of our tale. The header partial:

<% if logged_in? %>
Hiya, <%= current_user.name %>! You're looking mighty fine today!
<%=link_to “Log Out”, logout_path %>
<% else %>
<%= link_to “Log In”, login_path %>
<% end %>

This allows the user to logout from every page in our web application, not to mention, a sweet, homey greeting ?. But we still have one problem. How does our session know who our user is? For this, we will come full circle and revisit our sessions controller.

class SessionsController < ApplicationController
skip_before_action :login_required, :only => [:new, :create]

def new
@user = User.new
end

def create
user = User.find_by_email(params[:email])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
redirect_to root_path, :notice => “Welcome back, #{user.email}”
else
flash.now.alert = “Invalid email or password”
render “new”
end
end

def destroy
session[:user_id] = nil
redirect_to root_path
end

private
def login(user)
session[:user_id] = nil
end
end

Like all good tales, there was one quiet character hiding, softly apart from the rest. The user.id. And like a wise old woman, who knows all but is soft spoken, she hid away in the sessions create action. Yet, without this one line of code “session = user.id”, our entire sessions hash would break and fall apart. It's the link between the two controllers, between our database and our models, and also, the link between our application, and our user. And that my friends, is how you create sessions in rails. Stalking complete. Story over.

Blog post image: snouty-pride-thats-not-all-folks-snoutypig.png

!!!!SPECIAL NOTE YOU MUST READ!!!! Please add the following to your gem file:

gem 'bcrypt'

This will enable encryption of passwords. You will also need to rename the password column in your user's table schema to password_digest. Rails does the rest. Can you say MAGIC?!?!?!! Now, for reals!

Blog post image: thatsallfolks.gif

This post originally appeared on Becca Ades's blog. Read more at A Coder's Journey.

About Flatiron School

More articles by Flatiron School