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
Top comments (0)