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)