Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save JohnathanWeisner/85953e9365a7358979ab to your computer and use it in GitHub Desktop.
Save JohnathanWeisner/85953e9365a7358979ab to your computer and use it in GitHub Desktop.

All of the commands that start with '$' should be done in the terminal with out the '$' part.

As an example when you see:

$rails c

You should type

rails c

into the terminal ##step 1:

Add this line to your gemfile

gem 'devise'

##step 2: Run:

$bundle install

##step 3:

Next we're going to run a generator to install devise.

$rails generate devise:install

##step 4:

Following the directions shown in terminal...

Add the line

config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

between the config blocks in these two files.

job_board/config/environments/development.rb

job_board/config/environments/test.rb

Open up

/jobs_board/app/views/layouts/application.html.erb

Then we are going to add notifications below our nav bar and above the

<%= yield %>

with this bit of code:

  <p class="notice"><%= notice %></p>
  <p class="alert"><%= alert %></p>

We also want to specify what the root of our app will be for our website. Let's open up:

/job_board/config/routes.rb

and add the root. Your routes file should now look like this.

Rails.application.routes.draw do
  resources :jobs

  root to: "jobs#index"
end

##step 6:

We're going to make a new user model using a devise generator. This generator does a lot of work for you and I recommend taking a look at the files it generates.

$rails generate devise user

Lets also take the time now to go into the user model generated here and specify it's relationship with the Job model. Navigate to

/job_board/app/models/user.rb

and update the code to look like:

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  has_many :jobs
end

we just added

has_many :jobs

because a user can have many jobs. This will add a bunch of methods onto the user model for us so that we can access a user's jobs from an instance of a user. Phew! That was a mouthful. Basically what that means is you can do this:

@user = User.find(1)
@jobs = @user.jobs

and then @jobs would be a collection of all the jobs for the User with an id of 1.

While we are at it lets add a tag to the Job model. Navigate to

/job_board/app/models/job.rb

and add the tag:

belongs_to :user

because a job posting belongs to the user who created it.

##step 7:

Next we're going to add a new column on to the jobs table in our database. This column is actually a foreign key which identifies which user a job post belongs to.

Run the generator command in your terminal.

$rails g migration add_user_id_to_job user_id:integer

We already have jobs in our database which don't have a user_id assigned to their columns so in an attempt to keep things as simple as possible we will drop our database, create a new one, and re-migrate the database with these terminal commands

$rake db:drop
$rake db:create
$rake db:migrate

##step 8:

Within rails there is a sessions hash which is basically a way to add things and look for things within the user’s cookie file stored on their computer.

You should read up on what a session is here: http://guides.rubyonrails.org/security.html#sessions

This is how devise keeps track of whether a user is signed in or not.

##Step 9:

Now we are going to add sign in/sign up buttons to our nav bar.

Run in your terminal:

$rake routes

to see the new routes devise has made for you.

Then within your nav/bar add these links above the add job link.

Open up:

/job_board/app/views/layouts/application.html.erb

and add:

<div class="right-nav">
  <ul>
    <li><%= link_to "Sign In", new_user_session_path %></li>
    <li><%= link_to "Sign Up", new_user_registration_path %></li>
    <li><%= link_to "Add Job", new_job_path %></li>
  </ul>
</div>

step 9:

Modify the css in the file /job_board/app/assets/stylesheets/nav.css.scss

We are adding the li {} css block and adding on to the a{} block.

li {
    float: right;
}
a {
    display: block;
    width: 70px;
    text-decoration: none;
    font-weight: bold;
    color: white;
  }

##step 10:

Devise makes a bunch of helper methods for you to use while authenticating and authorizing users. For a full list of these helper methods go to the docs.

https://github.com/plataformatec/devise

user_signed_in? is a method that checks to see if the user is currently logged in. We are going to use a ruby ‘if’ statement to give the user the option to log out if they are signed in and sign in or sign up if they aren’t currently logged in.

Add logout button

Open up: /job_board/app/views/layouts/application.html.erb

  <header>
    <div class="left-nav">
      <ul>
        <li><%= link_to "Home", jobs_path %></li>
      </ul>
    </div>
    <div class="right-nav">
      <ul>
        <% if user_signed_in? %>
          <li><%= link_to "Add Job", new_job_path %></li>
          <li><%= link_to('Logout', destroy_user_session_path, :method => :delete) %></li>
        <% else %>
          <li><%= link_to "Sign In", new_user_session_path %></li>
          <li><%= link_to "Sign Up", new_user_registration_path %></li>
        <% end %>
      </ul>
    </div>
    <div class="clearfix"></div>
  </header>

##step 11:

We are now going to add a call back to our jobs controller

/job_board/app/controllers/jobs_controller.rb
class JobsController < ApplicationController
  before_action :authenticate_user!

A call back is a type of hook that gets called when something happens. That’s a rather vague description because there are many types and uses for call backs.

The call back before_action by default happens before any of the actions within the JobsController get called.

This would be great if we wanted to prevent people from seeing any of the jobs before they logged in, but in this case we are going to want to let the users see the index even if they aren’t logged in.

Let’s change the before_action to check if the user is signed in except for the index action.

/job_board/app/controllers/jobs_controller.rb
before_action :authenticate_user!, except: [:index]

##step 14:

Only the user who posted the job sees the edit and delete links

/job_board/app/views/jobs/index.html.erb

We are going to add some code that will check to see if the current user (the user signed in) is the user that created the job. Within the each loop add the following condition around the edit and delete links

  <% if user_signed_in? && job.user.id == current_user.id %>
    <h5><%= link_to "Edit Posting", edit_job_path(job)%></h5>
    <h5><%= link_to 'Delete Posting', job, method: :delete %></h5>
  <% end %>

##step 13:

That last step made it so that users who didn’t create the job posts wouldn’t see the links for editing and deleting the jobs, but they can still go to the routes

/jobs/1/edit
/jobs/1/delete

and manipulate the posts.

To prevent that and in the spirit of keeping things DRY we are going to use another before_action call back.

This before_action will call a method of our own creation which checks to see if this user is the owner of the job they are trying to edit, update, or delete. Lets change the code to look like this.

before_action :authenticate_user!, except: [:index]
before_action :authorize_user_for_job!, only: [:edit, :update, :delete]

and then at the bottom of our class Job after the very last end in our file we will write the code for the method the before_action calls.

def authorize_user_for_job!
  @job = Job.find(params[:id])
  redirect_to jobs_path unless current_user == job.user
end
@job = Job.find(params[:id])

We can also remove the line above from the edit, update and delete actions because our before_action call back finds the job for us.

Now only the user who created the job post can go to the

jobs/:id/edit 
jobs/:id/delete

routes.

#Congratulations! You have your first app with user autherization and authentication.

If you have any questions or suggestions feel free to email me at joweisner@gmail.com

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