Day 54 : #100DaysofCode -Review on setting up log in & sign up
Published: 2020-07-25 00:14:04

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.

<h2> 1. Create Branch </h2>
First you should create a new branch, just to be safe!

``git checkout -b user_setup``

<h2> 2. Generate User Resource </h2>

Run the following code: 

``rails g resource User name username password_digest``

which will generate a User MVC. 

<h2> 3. Add Unique User Id to Lists </h2>

``rails generate migration AddUserToLists user_id:integer``

which will add a user_id to be referenced in the List we created in my prior <a href="https://dev.to/sincerelybrittany/day-49-100daysofcode-still-coding-along-bb8">post.</a>

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

<h3> <center> Make sure to migrate your table! </center></h3>

<h2> 4. Gemfile </h2>
Next, make sure to go to your gemfile and add/uncomment the ``bycrypt`` gem. 

<h2> 5. Models </h2>
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
```

<h2> 6. Check it all out in rails console </h2>

```
m = User.new(name: "Sincerely", username: "brittany", password: "password")
m.save
```
Should return <b>true</b>

<h2> Add some validations in your model </h2>

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

<h2> Check it out in rails console </h2>

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

should return <b>false</b> <i>(because of validations)</i>

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 <b>true</b>

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.

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

<h3><center> NEXT: M-V-C Let's create the sign up </center></h3>

<h2> 7. Create new route in <i>config/routes.rb</i>: </h2>

```
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'
```

<h2> 8. Create new user instance in controller </h2>

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

<h2> 9. Set up your signup view page: </h2>

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

<h2> 10. Now update your create method in user </h2>

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

<h2> 11. Lets work on our application view </h2>
```
   <header>
       <%= navbar %>
  </header>
```
 <h2> Lets create a create a helper named ``navbar`` </h2>
```
   def navbar
        if logged_in?
            render "layouts/logged_in_navbar"
        else
            render "layouts/logged_out_navbar"
        end 
    end 
```
 <h2> 12. Now, we have to create the helper methods, logged_in and current user in the application controller: </h2>

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


<h2> 13. Create the two layout partials mentioned in your navbar helper </h2>

<i>logged_in partial</i> 

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

<i> logged_out partial</i> 

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

  <h2> 14. Update the routes </h2>

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

<h2> 15. Create a sessions controller </h2>

``rails g controller sessions ``

<h2> 16. Create a <i>sessions/new</i> view </h2>

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

<h2> Update your sessions controller to have flash messages! </h2>

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

<h2> 17. Update your application_controller </h2>

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

    def authenticate
        redirect_to login_path if !logged_in?
    end 
```

  <h2> 18. Update your ``application.html.erb`` to show the flash messages </h2>

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