DEV Community

Brittany
Brittany

Posted on

3 1

Day 54 : #100DaysofCode -Review on setting up log in & sign up

As promised, I am going to review how I added user authentication functionality onto my simple todo application and hopefully tomorrow I will be able to share how I added user authorization.

1. Create Branch

First you should create a new branch, just to be safe!

git checkout -b user_setup

2. Generate User Resource

Run the following code:

rails g resource User name username password_digest

which will generate a User MVC.

3. Add Unique User Id to Lists

rails generate migration AddUserToLists user_id:integer

which will add a user_id to be referenced in the List we created in my prior post.

Check out the schema, it should look similar to this:

ActiveRecord::Schema.define(version: 2020_07_24_000911) do

  create_table "items", force: :cascade do |t|
    t.string "description"
    t.integer "list_id"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.integer "status", default: 0
  end

  create_table "lists", force: :cascade do |t|
    t.string "name"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.integer "user_id"
  end

  create_table "users", force: :cascade do |t|
    t.string "name"
    t.string "username"
    t.string "password_digest"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

end
Enter fullscreen mode Exit fullscreen mode

Make sure to migrate your table!

4. Gemfile

Next, make sure to go to your gemfile and add/uncomment the bycrypt gem.

5. Models

Next we want to set up our models.

Your user model should have many lists and have a secure password:

class User < ApplicationRecord
    has_secure_password
    has_many :lists
end
Enter fullscreen mode Exit fullscreen mode

Your list model should belong_to user:

class List < ApplicationRecord
    belongs_to :user
    has_many :items
end
Enter fullscreen mode Exit fullscreen mode

6. Check it all out in rails console

m = User.new(name: "Sincerely", username: "brittany", password: "password")
m.save
Enter fullscreen mode Exit fullscreen mode

Should return true

Add some validations in your model

class User < ApplicationRecord
    has_secure_password
    validates :username, uniqueness: true
    has_many :lists
end
Enter fullscreen mode Exit fullscreen mode
class List < ApplicationRecord
    belongs_to :user
    has_many :items
    validates :name, presence: true
end
Enter fullscreen mode Exit fullscreen mode

Check it out in rails console

n = User.new(name: "steve", username: "brittany", password: "password")
n.save 
Enter fullscreen mode Exit fullscreen mode

should return false (because of validations)

If you run the following:

n.errors 
Enter fullscreen mode Exit fullscreen mode

it should return => username already taken confirming our validations are up and working.

Let's update the username of n so that it will save.

n.username = "steve"
n.save
Enter fullscreen mode Exit fullscreen mode

Now that should return true

We've created some list in the past, lets see what we've made:

List.all

a = List.first
a.user_id = n.id - sets the List_id to user 1 id.
a.save

b = List.find(2).user_id = m.id
b.save - sets the List_id to user 2 id.

P.S. - If you have no list create a list and add a user:
p = List.create(name: "this is a list")
p.user_id = n.id
p.save

NEXT: M-V-C Let's create the sign up

7. Create new route in config/routes.rb:

get "/signup" => "users#new", as: "signup"
Enter fullscreen mode Exit fullscreen mode

So now your routes should look something like this:

  resources :users, except: [:new]
  get 'items/create'
  resources :lists do 
    resources :items
  end 
  get "/signup" => "users#new", as: "signup"
  root 'lists#index'
Enter fullscreen mode Exit fullscreen mode

8. Create new user instance in controller

class UsersController < ApplicationController
    def new
        @user = User.new
    end 
end
Enter fullscreen mode Exit fullscreen mode

9. Set up your signup view page:

<%= form_with model: @user, local: true do |f| %>
<%= f.text_field :name, placeholder: "name" %>
<%= f.text_field :name, placeholder: "username" %>
<%= f.password_field :name, placeholder: "password" %>
<%= f.submit %>
<% end %>
Enter fullscreen mode Exit fullscreen mode

10. Now update your create method in user

   def create
        @user = User.new(user_params)
        if @user.save 
            session[:user_id] = @user.id #logs in the user -- tells app that user is logged in
            redirect_to lists_path
        else 
            render :new
        end 
    end
Enter fullscreen mode Exit fullscreen mode

11. Lets work on our application view

   <header>
       <%= navbar %>
  </header>
Enter fullscreen mode Exit fullscreen mode

Lets create a create a helper named navbar


   def navbar
        if logged_in?
            render "layouts/logged_in_navbar"
        else
            render "layouts/logged_out_navbar"
        end 
    end 
Enter fullscreen mode Exit fullscreen mode

12. Now, we have to create the helper methods, logged_in and current user in the application controller:


      helper_method :logged_in?
      helper_method :current_user

    private

    def logged_in?
        !!current_user
    end 

    def current_user
        User.find_by(id: session[:user_id])
    end 
Enter fullscreen mode Exit fullscreen mode

13. Create the two layout partials mentioned in your navbar helper

logged_in partial

    <%= button_to 'Log Out', '/logout', method: :delete %>
Enter fullscreen mode Exit fullscreen mode

logged_out partial

  <%= link_to 'Log In', login_path %>
  <%= link_to 'Sign Up', signup_path %>
Enter fullscreen mode Exit fullscreen mode

14. Update the routes


  Rails.application.routes.draw do
  root 'lists#index'
  resources :users, except: [:new]

  get "/signup" => "users#new", as: "signup"
  get "/login" => "sessions#new", as: "login"
  post "/login" => "sessions#create"
  delete "/logout" => "sessions#destroy"

  get 'items/create'
  resources :lists do 
    resources :items
  end 
end
Enter fullscreen mode Exit fullscreen mode

15. Create a sessions controller

rails g controller sessions

16. Create a sessions/new view

<%= form_tag("/login") do %>
<%= text_field_tag :username,nil, placeholder: 'username'%>
<%= password_field_tag :password, nil, placeholder: 'password' %>
<%= submit_tag "Login"%>
<% end %>
Enter fullscreen mode Exit fullscreen mode

Update your sessions controller to have flash messages!

 def create 
        @user = User.find_by(username: params[:username])
        if @user && @user.authenticate(params[:password])
            # session[:user_id]
            log_in(@user)
            flash[:sucess] = "Welcome, #{@user.username}"
            redirect_to lists_path
        else 
            flash[:danger] = "Improper credentials given"
            redirect_to login_path
        end 
    end
Enter fullscreen mode Exit fullscreen mode

17. Update your application_controller

    def log_in(user)
        session[:user_id] = user.id
    end 

    def authenticate
        redirect_to login_path if !logged_in?
    end 
Enter fullscreen mode Exit fullscreen mode

18. Update your application.html.erb to show the flash messages


    <header>
  <% flash.each do |k,v| %>
    <%= v %>
    <% end %>
  <%= navbar %>
  </header>
    <%= yield %>
Enter fullscreen mode Exit fullscreen mode

And you have now implemented user authorization on your application.

Thanks for reading!

Sincerely,
Brittany

Image of Datadog

Create and maintain end-to-end frontend tests

Learn best practices on creating frontend tests, testing on-premise apps, integrating tests into your CI/CD pipeline, and using Datadog’s testing tunnel.

Download The Guide

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay