Learning To Code

An Epic Adventure: How to Create Sessions in Rails

Flatiron School / 6 August 2015
SHARE:

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?

Once upon a time

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.

1
2
3
4
5
6
  root 'posts#index'

  resources :sessions, only: [:create, :new, :destoy]
  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:

1
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:

1
2
3
4
5
6
7
8
  def new
  end

  def create
  end

  def destroy
  end

Here we go!

Luigi

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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  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:

1
2
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!!!!

The Holy Grail

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.

1
<%= render 'layouts/header' %>

Followed by the creation of “_header.html.erb”

Now, we are embarking on the climax of our tale. The header partial:

1
2
3
4
5
6
<% 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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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] = 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.

That's not all!

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

1
gem 'bcrypt'

This will enable encription 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!


thatsallfolks

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

Flatiron Alumni Presents App in White House Previous Post Flatiron + Nitrous Partner for Pre-College Programs Next Post