Skip to content

Instantly share code, notes, and snippets.

@kcurbelo
Last active August 29, 2015 14:15
Show Gist options
  • Save kcurbelo/811dae330d39a78827f5 to your computer and use it in GitHub Desktop.
Save kcurbelo/811dae330d39a78827f5 to your computer and use it in GitHub Desktop.
An authentication example.

Authentication


This is a quick guide to get a very basic user login up and running.

First we will need to make a folder to work in. For the purposes of this guide I called mine "authentication" but you can call yours whatever you would like. Be sure to "cd" into this directory after you create it.

command line - $ mkdir authentication

command line - $ cd authentication

Now that we are in our directory we can start a new rails project.

$ rails new authentication

(Your rails project doesn't have to be named the same as the directory that you create)

You are going to want to cd into your newly created rails project.

$ cd authentication

To check to see if you are in the right folder

$ pwd

or

$ ls (You should see all the files it generated)

Next we are going to generate the model for our user and the labels for our table at the same time. When creating a model the name you give it is capitalized and singular i.e "User".

$ rails g model User first_name email password_digest

(If it blew up in your face make sure that you "cd" into your rails project)

Open the directory in any text editor that you would like. The navigate to your models folder.

You should get this in your model file (it is empty because we have done anything except create it):

class User < ActiveRecord::Base
end

Let's do a rake db:migrate to create the table we just made.

$ rake db:migrate

If you go to your "db" folder, your schema has now been generated:

ActiveRecord::Schema.define(version: 20150214013832) do

  create_table "users", force: true do |t|
    t.string   "email"
    t.string   "first_name"
    t.string   "password_digest"
    t.datetime "created_at",      null: false
    t.datetime "updated_at",      null: false
  end

end

Remember the labels after our model name? There they are in our schema.

Now we can generate the controller of our User model.

$ rails g controller users

When creating a controller it is all lower case and plural i.e users.

This is what your users_controller.rb should look like:

class UsersController < ApplicationController
end

Now let's start setting up our security code using the bcrypt gem.

Navigate to your "Gemfile" and uncomment the gem.

# Use ActiveModel has_secure_password
gem 'bcrypt', '~> 3.1.7'

We have to run a bundle in order install the gem.

$ bundle

Let's go to our user.rb file in our models folder and add in some code. Make sure that "require 'bcrypt'" comes before everything.

require 'bcrypt'
class User < ActiveRecord::Base
  has_secure_password #made available from the bcrypt gem
end

How about we create some test users?

Fire up the rails console in the command land:

$ rails c

There are three ways we could do create a user:

u = User.new(email:"[email protected]")
u.password="ilovetacos"
u.first_name = "Joe"
u.save
u2 = User.create(first_name:"Bono", email:"[email protected]", password: "rockandroll")
u3 = User.new(first_name:"Bob", email:"[email protected]", password: "whataboutbob")
u3.save

We can see how many users we have by running:

User.count

We could also see all the information of our users by running:

User.all

If you want to do a quick test to make sure the authentication works, you could run:

u2.authenticate('weird')

This should return false because our u2's (second user we created) password isn't "weird".

However, if we run:

u2.authenticate('rockandroll')

It will return true because the password of u2 was "rockandroll".

Changing gears, lets exit the rails console and enter the users_controller.rb. Here we will need to add in the "new", "create", and "show" methods:

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

  def create
    user = User.new(params.require(:user).permit(:first_name, :email, :password)) #which inputs will be allowed in the create controller
    if user.save
      redirect_to new_session_path(user_created: 'true') #someone logs in here
    end
  end

  def show
    @user = User.find(session['user_id'])
  end
end

In order to see something we will need to add a view. Lets do that now in our users view:

First up is the new view. Add a file called new.html.erb in the "users" folder which is inside your "views" folder.

<h1>Sign up!</h1>

<%= form_for @user do |f|%>
    First name: <%= f.text_field :first_name %><br />
    E-mail: <%= f.text_field :email %><br />
    Password: <%= f.password_field :password %><br />
    Password confirmation: <%= f.password_field :password_confirmation %><br />

    <%=f.submit %>

<% end %>

Lets add another that will render a show page after they log in, let's call it show.html.erb.

<h1>Welcome to your use page <%= @user.email%> !</h1>
<p>You are now logged in.</p>
<p>E-mail:</p>
<%= @user.email %>

We now have to create a controller for our users session once they log in.

To generate the controller:

$ rails g controller sessions new create destroy

Our last bit of code generated a controller for sessions with the "new", "create", and "destroy". Not only that but it generated the views for those methods as well.

We wont be using the create or destroy view, so go into your "sessions" folder inside the "views" folder and delete "create.html.erb" and "destroy.html.erb"

In order for our users to login we will need them to have a place to login.

Go into the "new.html.erb" in the "sessions" folder and add in the user sign in code:

<h1>Sessions#new</h1>
<p>Find me in app/views/sessions/new.html.erb</p>

<h3> <%= @user_created_message %> </h3>

<h1>Log-in!</h1>

<%= form_for @user, :url => { :controller => "sessions", :action => "create" } do |f| %> <!-- See the comment under the f.submit line for details. the url tells it to go to the sessions path, create method instead-->
    E-mail: <%= f.text_field :email %><br />
    Password: <%= f.password_field :password %><br />
    <%=f.submit 'Log yourself in' %> <!-- This will post back to the users controller by default because it's a user. We need to override this behavior -->

<% end %>

<%= link_to 'New user? Create an account here', new_user_path %>

It should look very similar to something you have seen before. We had copied over this code from your users new.html.erb and made some slight edits.

We have to edit our sessions controller so that way our session will begin to work.

It should look like:

class SessionsController < ApplicationController
  def new
    @user = User.new #Any controller can create something from any other model!
    if params[:user_created] == 'true'
      @user_created_message = 'User successfully created!'
    end
  end


  def create
    # raise params.inspect
    #Find the user by email
    u = User.where(email: params[:user][:email]).first #in the params hash, you can pick up the user hash, within which you can pick up the email key-value pair
    if u !=nil && u.authenticate(params[:user][:password]) #check that there is a user found and the password is correct
      session['user_id'] = u.id.to_s # hold on to idea that you are logged in, which is the session state. This is a special rails magic thing. This capitalized session has nothing to do with a model or even this controller which is called sessions. The Session in this case refers to something in Rails that essentially is a cookie that will be passed around as long as the next page renders correctly
      redirect_to user_path(u) #should redirect to a dashboard. Just want to redirect to a page that we currently have
    end
  end

  def destroy
    session.destroy
    redirect_to new_session_path
  end
end

We have done quite a bit of setting up! The last thing we need to do is make sure everything we set up knows where to go. We can do this by editing our routes.

In the configuration folder, toward the bottom, our routes folder will help set up the connections.

You should see something like this:

  get 'sessions/new'

  get 'sessions/create'

  get 'sessions/destroy'

We wont be needing these. Lets replace them with something that will help us wire all of our different components together.

Replace the existing code with:

  root to: 'sessions#new'

  delete '/sessions' => 'sessions#destroy', as: 'logout'
  resources :sessions, only: [:new, :create, :destroy]

  resources :users, only: [:index, :new, :create, :show]

Add an inspect element to the application.html.erb in the layouts folder to see which user is currently logged in:

<%= session["user_id"].inspect %>

Now it's time to see all that hard work!

Start up the rails server:

$ rails s

Go to your web browser and in the url type in:

localhost:3000

You're all done with you simple authentication app!


###Extra - Adding a log out function

We can add a sign out function quickly by adding in a few more bits of code.

First we will need to create something that will allow us to be able to access the person that is currently logged in.

Let's do this by going into our applications controller and adding:

  helper_method :current_user
  def current_user
    User.where(id: session["user_id"]).first
  end

It should look something similar to this:

class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception
  
  helper_method :current_user

  def current_user
    User.where(id: session["user_id"]).first
  end
end

Next, let's use the newly created "current user" helper method to sign our user out, in the application.html.erb:

<% if current_user != nil %>
This is the person who's logged in: <%= current_user.email %>
<%= button_to "Log out", session_path, method: :delete %>
<% else %>
<%= button_to "Sign up", new_user_path, method: :get %>
<% end %>

You could add this code anywhere in the bdy section of the html. I have added it before the <% yield %>, so that way it will be before any generated content.

For example:

<body>

  <% if current_user != nil %>
    This is the person who's logged in: <%= current_user.email %>
    <%= button_to "Log out", session_path, method: :delete %>
  <% else %>
    <%= button_to "Sign up", new_user_path, method: :get %>
  <% end %>

  <%= yield %>

</body>

Contributors:

Wendy Gwo - https://github.com/wendygwo

Lorin Thwaits

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