Commit 5429628

Stephen Peasley <s@stephenpeasley.com>
2015-01-24 17:01:56
First cut of user authentication
1 parent 191a232
app/controllers/registrations_controller.rb
@@ -1,4 +1,7 @@
 class RegistrationsController < ApplicationController
+  
+  layout "public"
+  
   def new
     @user = User.new
   end
app/controllers/sessions_controller.rb
@@ -1,8 +1,15 @@
 class SessionsController < ApplicationController
   
+  layout "public"
+  
+  def create
+    session[:user_id] = User.authenticate(params[:email], params[:password]).id
+    render :nothing => true
+  end
+  
   def destroy
     reset_session()
-    render :nothing => true
+    redirect_to root_path
   end
   
 end
app/models/user.rb
@@ -1,8 +1,15 @@
 class User < ActiveRecord::Base
-  attr_accessor :password
+  has_secure_password
   USERNAME_REGEX=/\A[-a-z0-9_.]*\z/i
 
   validates :username, presence: true, format: { with: USERNAME_REGEX }, uniqueness: true
   validates :email, presence: true, email: true, uniqueness: true
   validates_acceptance_of :terms_and_conditions
+  
+  def self.authenticate(email,password)
+    if user = User.find_by(email: email)
+      user.authenticate(password)
+    end
+  end
+  
 end
app/views/layouts/application.html.erb
@@ -10,7 +10,222 @@
   </head>
   <body>
     <%= render partial: 'layouts/flash' %>
-    <%= yield %>
+    <div class="row">
+      <div class="large-12 columns">
+   
+      <!-- Navigation -->
+        <div class="row">
+          <div class="large-12 columns">
+   
+            <nav class="top-bar" data-topbar>
+              <ul class="title-area">
+                <!-- Title Area -->
+                <li class="name">
+                  <h1>
+                    <a href="#">
+                      Supply
+                    </a>
+                  </h1>
+                </li>
+                <li class="toggle-topbar menu-icon"><a href="#"><span>menu</span></a></li>
+              </ul>
+           
+              <section class="top-bar-section">
+                <!-- Right Nav Section -->
+                <ul class="right">
+                  <li class="divider"></li>
+                  <li class="has-dropdown">
+                    <a href="#">Main Item 1</a>
+                    <ul class="dropdown">
+                      <li><label>Section Name</label></li>
+                      <li class="has-dropdown">
+                        <a href="#" class="">Has Dropdown, Level 1</a>
+                        <ul class="dropdown">
+                          <li><a href="#">Dropdown Options</a></li>
+                          <li><a href="#">Dropdown Options</a></li>
+                          <li><a href="#">Level 2</a></li>
+                          <li><a href="#">Subdropdown Option</a></li>
+                          <li><a href="#">Subdropdown Option</a></li>
+                          <li><a href="#">Subdropdown Option</a></li>
+                        </ul>
+                      </li>
+                      <li><a href="#">Dropdown Option</a></li>
+                      <li><a href="#">Dropdown Option</a></li>
+                      <li class="divider"></li>
+                      <li><label>Section Name</label></li>
+                      <li><a href="#">Dropdown Option</a></li>
+                      <li><a href="#">Dropdown Option</a></li>
+                      <li><a href="#">Dropdown Option</a></li>
+                      <li class="divider"></li>
+                      <li><a href="#">See all →</a></li>
+                    </ul>
+                  </li>
+                  <li class="divider"></li>
+                  <li><a href="#">Main Item 2</a></li>
+                  <li class="divider"></li>
+                  <li class="has-dropdown">
+                    <a href="#">Main Item 3</a>
+                    <ul class="dropdown">
+                      <li><a href="#">Dropdown Option</a></li>
+                      <li><a href="#">Dropdown Option</a></li>
+                      <li><a href="#">Dropdown Option</a></li>
+                      <li class="divider"></li>
+                      <li><a href="#">See all →</a></li>
+                    </ul>
+                  </li>
+                  <li class="divider"></li>
+                  <li><%# link_to "Logout", session_destroy_path(current_user), method: :delete %></li>
+                </ul>
+              </section>
+            </nav>
+            <!-- End Top Bar -->
+          </div>
+        </div>
+   
+      <!-- End Navigation -->
+   
+        <div class="row">
+   
+    <!-- Side Bar -->
+   
+          <div class="large-4 small-12 columns">
+   
+            <img src="http://placehold.it/500x500&text=Logo">
+   
+            <div class="hide-for-small panel">
+              <h3>Header</h3>
+              <h5 class="subheader">Risus ligula, aliquam nec fermentum vitae, sollicitudin eget urna. Donec dignissim nibh fermentum odio ornare sagittis.
+              </h5>
+            </div>
+   
+            <a href="#">
+            <div class="panel callout radius">
+              <h6>99  items in your cart</h6>
+            </div>
+            </a>
+   
+          </div>
+   
+      <!-- End Side Bar -->
+   
+   
+      <!-- Thumbnails -->
+   
+          <div class="large-8 columns">
+            <div class="row">
+   
+              <div class="large-4 small-6 columns">
+                <img src="http://placehold.it/1000x1000&text=Thumbnail">
+   
+                <div class="panel">
+                  <h5>Item Name</h5>
+                  <h6 class="subheader">$000.00</h6>
+                </div>
+              </div>
+   
+              <div class="large-4 small-6 columns">
+                <img src="http://placehold.it/500x500&text=Thumbnail">
+   
+                <div class="panel">
+                  <h5>Item Name</h5>
+                  <h6 class="subheader">$000.00</h6>
+                </div>
+              </div>
+   
+              <div class="large-4 small-6 columns">
+                <img src="http://placehold.it/500x500&text=Thumbnail">
+   
+                <div class="panel">
+                  <h5>Item Name</h5>
+                  <h6 class="subheader">$000.00</h6>
+                </div>
+              </div>
+   
+              <div class="large-4 small-6 columns">
+                <img src="http://placehold.it/500x500&text=Thumbnail">
+   
+                <div class="panel">
+                  <h5>Item Name</h5>
+                  <h6 class="subheader">$000.00</h6>
+                </div>
+              </div>
+   
+              <div class="large-4 small-6 columns">
+                <img src="http://placehold.it/500x500&text=Thumbnail">
+   
+                <div class="panel">
+                  <h5>Item Name</h5>
+                  <h6 class="subheader">$000.00</h6>
+                </div>
+              </div>
+   
+              <div class="large-4 small-6 columns">
+                <img src="http://placehold.it/500x500&text=Thumbnail">
+   
+                <div class="panel">
+                  <h5>Item Name</h5>
+                  <h6 class="subheader">$000.00</h6>
+                </div>
+              </div>
+            </div>
+   
+      <!-- End Thumbnails -->
+   
+   
+      <!-- Managed By -->
+            <div class="row">
+              <div class="large-12 columns">
+                <div class="panel">
+                  <div class="row">
+   
+                    <div class="large-2 small-6 columns">
+                      <img src="http://placehold.it/300x300&text=Site Owner">
+                    </div>
+   
+                    <div class="large-10 small-6 columns">
+                      <strong>This Site Is Managed By<hr/></strong>
+   
+                      Risus ligula, aliquam nec fermentum vitae, sollicitudin eget urna. Donec dignissim nibh fermentum odio ornare sagittis
+                    </div>
+   
+                  </div>
+                </div>
+              </div>
+   
+      <!-- End Managed By -->
+   
+            </div>
+          </div>
+        </div>
+   
+   
+      <!-- Footer -->
+   
+        <footer class="row">
+          <div class="large-12 columns"><hr />
+            <div class="row">
+   
+              <div class="large-6 columns">
+                <p>© Copyright no one at all. Go to town.</p>
+              </div>
+   
+              <div class="large-6 columns">
+                <ul class="inline-list right">
+                  <li><a href="#">Link 1</a></li>
+                  <li><a href="#">Link 2</a></li>
+                  <li><a href="#">Link 3</a></li>
+                  <li><a href="#">Link 4</a></li>
+                </ul>
+              </div>
+   
+            </div>
+          </div>
+        </footer>
+   
+      <!-- End Footer -->
+   
+      </div>
+    </div>
     <%= javascript_include_tag "application" %>
   </body>
 </html>
app/views/layouts/public.html.erb
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title><%= content_for?(:title) ? yield(:title) : "supply" %></title>
+    <%= stylesheet_link_tag    "application" %>
+    <%= javascript_include_tag "vendor/modernizr" %>
+    <%= csrf_meta_tags %>
+  </head>
+  <body>
+    <%= render partial: 'layouts/flash' %>
+    <%= yield %>
+    <%= javascript_include_tag "application" %>
+  </body>
+</html>
app/views/sessions/new.html.erb
@@ -1,1 +1,1 @@
-<%= link_to t('.register_button'), new_registration_path, class: "button secondary" %>
+<%= link_to t('.register_button'), new_registration_path, class: "button secondary" %>
\ No newline at end of file
config/routes.rb
@@ -1,6 +1,6 @@
 Rails.application.routes.draw do
   root 'sessions#new'
-  resources :sessions, only: [:new, :destroy]
+  resources :sessions, only: [:new, :create, :destroy]
   resources :registrations, only: [:new, :create]
   get '/' => 'sessions#new', as: :dashboard
   get "/terms" => "static_pages#terms"
db/migrate/20150124163233_add_password_digest_to_users.rb
@@ -0,0 +1,5 @@
+class AddPasswordDigestToUsers < ActiveRecord::Migration
+  def change
+    add_column :users, :password_digest, :string
+  end
+end
db/schema.rb
@@ -11,15 +11,16 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 20150103150805) do
+ActiveRecord::Schema.define(version: 20150124163233) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
   enable_extension "uuid-ossp"
 
   create_table "users", id: :uuid, default: "uuid_generate_v4()", force: :cascade do |t|
-    t.string "username", null: false
-    t.string "email",    null: false
+    t.string "username",        null: false
+    t.string "email",           null: false
+    t.string "password_digest"
   end
 
 end
spec/controllers/sessions_controller_spec.rb
@@ -2,6 +2,19 @@ require "rails_helper"
 
 describe SessionsController do
   
+  describe "#create" do
+    context "when credentials are correct" do
+      
+      let(:user) { create(:user, password: "password") }
+      
+      it "logs you in" do
+        post :create, { email: user.email, password: "password" }
+        expect(session[:user_id]).to eql(user.id)
+      end
+      
+    end
+  end
+  
   describe "#destroy" do
     context "when logged in" do
       
spec/factories/users.rb
@@ -2,6 +2,8 @@ FactoryGirl.define do
   factory :user do
     username Faker::Internet.user_name
     email Faker::Internet.email
+    password "password"
+    password_confirmation "password"
     terms_and_conditions "1"
   end
 end
spec/models/user_spec.rb
@@ -27,9 +27,9 @@ describe User do
       end
 
       it "is invalid if the username is already taken" do
-        User.create(username: "blah", email: "blah@example.com")
-        user = User.create(username: "blah", email: "blahblah@example.com")
-
+        create(:user, username: "blah", email: "blah@example.com")
+        user = build(:user, username: "blah", email: "blahblah@example.com")
+        expect(user).to_not be_valid
         expect(user.errors[:username]).to_not be_empty
       end
     end
@@ -48,9 +48,9 @@ describe User do
       end
 
       it "is invalid if the email address is already registered" do
-        User.create(username: "blahblah", email: "blah@example.com")
-        second_user = User.create(username: "blah", email: "blah@example.com")
-
+        create(:user, username: "blahblah", email: "blah@example.com")
+        second_user = build(:user, username: "blah", email: "blah@example.com")
+        expect(second_user).to_not be_valid
         expect(second_user.errors[:email]).to_not be_empty
       end
     end
@@ -88,4 +88,16 @@ describe User do
       expect(User::USERNAME_REGEX).to match("username1")
     end
   end
+  
+  describe "#authenticate" do
+    context "retuns true when credentials are correct" do
+      
+      it "returns true" do
+        user = create(:user, password: "password", password_confirmation: "password")
+        expect(User.authenticate(user.email, "password")).to eql(user)
+      end
+      
+    end
+  end
+  
 end
Gemfile
@@ -26,7 +26,7 @@ gem 'foundation-rails'
 gem 'email_validator'
 
 # Use ActiveModel has_secure_password
-# gem 'bcrypt', '~> 3.1.7'
+gem 'bcrypt', '~> 3.1.7'
 
 # Use Unicorn as the app server
 gem 'unicorn'
Gemfile.lock
@@ -37,6 +37,7 @@ GEM
       thread_safe (~> 0.3, >= 0.3.4)
       tzinfo (~> 1.1)
     arel (6.0.0)
+    bcrypt (3.1.9)
     binding_of_caller (0.7.2)
       debug_inspector (>= 0.0.1)
     builder (3.2.2)
@@ -230,6 +231,7 @@ PLATFORMS
   ruby
 
 DEPENDENCIES
+  bcrypt (~> 3.1.7)
   byebug
   coffee-rails (~> 4.1.0)
   database_cleaner