loading...

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

sincerelybrittany profile image Brittany ・4 min read

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

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

Your list model should belong_to user:

class List < ApplicationRecord
    belongs_to :user
    has_many :items
end

6. Check it all out in rails console

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

Should return true

Add some validations in your model

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

Check it out in rails console

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

should return false (because of validations)

If you run the following:

n.errors 

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

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"

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'

8. Create new user instance in controller

class UsersController < ApplicationController
    def new
        @user = User.new
    end 
end

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 %>

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

11. Lets work on our application view

   <header>
       <%= navbar %>
  </header>

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 

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 

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

logged_in partial

    <%= button_to 'Log Out', '/logout', method: :delete %>

logged_out partial

  <%= link_to 'Log In', login_path %>
  <%= link_to 'Sign Up', signup_path %>

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

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 %>

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

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 

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


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

And you have now implemented user authorization on your application.

Thanks for reading!

Sincerely,
Brittany

Posted on by:

sincerelybrittany profile

Brittany

@sincerelybrittany

Developer | Software Engineer 👩🏾‍💻 | Determined | Music & Dance | Completed #100DaysofCode | #WomenWhoCode

Discussion

markdown guide