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