Skip to content

Instantly share code, notes, and snippets.

@mdang
Last active May 24, 2020 08:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mdang/7b6097cc13b07db82c78 to your computer and use it in GitHub Desktop.
Save mdang/7b6097cc13b07db82c78 to your computer and use it in GitHub Desktop.
Lesson: User Auth (Rails Example)

User Auth with Rails (The Fun Way)

Starting a new project

$ rails new user_auth --database=postgresql
$ cd user_auth
$ rake db:create

Adding the users model and database table

$ rails g model User

Update the migration file with the columns we need

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.text :first_name, null: false
      t.text :last_name, null: false
      t.text :email, null: false, unique: true
      t.text :password_digest, null: false

      t.timestamps null: false
    end

    add_index :users, :email, unique: true
  end
end

Run the migration file to add the table to the database

$ rake db:migrate

Including the bcrypt gem

https://github.com/codahale/bcrypt-ruby

In the Gemfile, uncomment the bcrypt gem and run bundle install

# Gemfile
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'
$ bundle install

Updating the user model

# app/models/user.rb
class User < ActiveRecord::Base
	# attributes
	attr_accessor :password

	# check to see if a supplied user password matches the hashed version in the database
	def authenticate(password)
		if BCrypt::Password.new(self.password_digest) == password
			true
		else
			false
		end
	end

	# Create a bcrypt hashed version of a plain text password
	def hash_password
		if password.present?
			return self.password_digest = BCrypt::Password.create(password)
		end
	end
end

Create and run the database seeds file

# db/seeds.rb
user = User.new({ :first_name => "Cookie", :last_name => "Monster", :email => "cookie@monster.com", :password => "cookie" })
user.hash_password
user.save
$ rake db:seed

Stop and check the database, make sure the hashing function and seeds file ran correctly

Creating the login controller

$ rails g controller login

Add the action

# app/controllers/login_controller.rb
class LoginController < ApplicationController
	def login_form

	end

	def check_login
		user = User.find_by(:email => params[:email])

		if user && user.authenticate(params[:password])
			# Valid login, set the session and redirect to protected destination
			session[:current_user_id] = user.id

			redirect_to '/'
		else 
			# Not a match, redirect to the login page 
			redirect_to '/login?err=1'
		end
	end
end

Add a route to the form

# config/routes.rb
get '/login' => 'login#login_form'
post '/login' => 'login#check_login'

Creating the login form

Create the view

<!-- app/views/login/login_form.html.erb -->
<h3>Login Form</h3>
<%= form_tag("/login", method: "post") do %>
	<div>
		<input type="text" name="email" placeholder="Enter your email address" />
	</div>

	<div>
		<input type="password" name="password" placeholder="Enter your password" />
	</div>

  	<%= submit_tag("Login") %>
<% end %>

Adding code that checks for a logged in user

# protected controller action
def protected_view
   current_user = User.find(session[:current_user_id])
   
   # If there's no user, then redirect them to the log in page
   # Note: In a real application you wouldn't want to duplicate this code on each call, use a filter
   if !current_user 
   	redirect_to '/login'
   end
end

The incomplete alternative that you should continue with:

class PhotosController < ApplicationController
  before_action :require_login
 
  private
 
  def require_login
    unless logged_in?
      flash[:error] = "You must be logged in to access this section"
      redirect_to '/login' # halts request cycle
    end
  end
end

Reference: http://guides.rubyonrails.org/action_controller_overview.html

Alternatives

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment