Agile Web Development with Rails, Edition 4

Agile Web Development with Rails, Edition 4

13.2 Iteration H2: Authenticating Users 12.8 Iteration J3: Integration Tests

13.1 Iteration H1: Adding Users

rails generate scaffold User name:string hashed_password:string salt:string
DEPRECATION WARNING: railtie_name is deprecated and has no effect. (called from <class:Railtie> at /home/rubys/.rvm/gems/ruby-1.9.3-r28190/gems/will_paginate-3.0.pre/lib/will_paginate/railtie.rb:6)
      invoke  active_record
      create    db/migrate/20100606143929_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/unit/user_test.rb
      create      test/fixtures/users.yml
       route  resources :users
      invoke  scaffold_controller
      create    app/controllers/users_controller.rb
      invoke    erb
      create      app/views/users
      create      app/views/users/index.html.erb
      create      app/views/users/edit.html.erb
      create      app/views/users/show.html.erb
      create      app/views/users/new.html.erb
      create      app/views/users/_form.html.erb
      invoke    test_unit
      create      test/functional/users_controller_test.rb
      invoke    helper
      create      app/helpers/users_helper.rb
      invoke      test_unit
      create        test/unit/helpers/users_helper_test.rb
      invoke  stylesheets
   identical    public/stylesheets/scaffold.css
rake db:migrate
mv 20100606143929_create_users.rb 20100301000008_create_users.rb
DEPRECATION WARNING: railtie_name is deprecated and has no effect. (called from <class:Railtie> at /home/rubys/.rvm/gems/ruby-1.9.3-r28190/gems/will_paginate-3.0.pre/lib/will_paginate/railtie.rb:6)
(in /home/rubys/svn/rails4/Book/util/work-193/depot)
==  CreateUsers: migrating ====================================================
-- create_table(:users)
   -> 0.0018s
==  CreateUsers: migrated (0.0019s) ===========================================
 
edit app/models/user.rb
require 'digest/sha1'
 
class User < ActiveRecord::Base
  validates :name, :presence => true, :uniqueness => true
 
  validates :password, :confirmation => true
  attr_accessor :password_confirmation
  attr_reader   :password
 
  validate  :password_must_be_present
  
  class << self
    def authenticate(name, password)
      if user = find_by_name(name)
        if user.hashed_password == encrypt_password(password, user.salt)
          user
        end
      end
    end
 
    def encrypt_password(password, salt)
      Digest::SHA1.hexdigest(password + "wibble" + salt)
    end
  end
  
  # 'password' is a virtual attribute
  def password=(password)
    @password = password
 
    if password.present?
      self.salt = generate_salt
      self.hashed_password = self.class.encrypt_password(password, salt)
    end
  end
  
  private
 
    def password_must_be_present
      errors.add(:password, "Missing password") unless hashed_password.present?
    end
  
    def generate_salt
      self.salt = self.object_id.to_s + rand.to_s
    end
end
edit app/controllers/users_controller.rb
  def create
    @user = User.new(params[:user])
 
    respond_to do |format|
      if @user.save
        format.html { redirect_to(users_url,
          :notice => "User #{@user.name} was successfully created.") }
        format.xml  { render :xml => @user,
          :status => :created, :location => @user }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @user.errors,
          :status => :unprocessable_entity }
      end
    end
  end
edit app/controllers/users_controller.rb
  def update
    @user = User.find(params[:id])
 
    respond_to do |format|
      if @user.update_attributes(params[:user])
        format.html { redirect_to(users_url,
          :notice => "User #{@user.name} was successfully updated.") }
        format.xml  { head :ok }
      else
        format.html { render :action => "edit" }
        format.xml  { render :xml => @user.errors,
          :status => :unprocessable_entity }
      end
    end
  end
edit app/controllers/users_controller.rb
  def index
    @users = User.order(:name)
 
    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @users }
    end
  end
edit app/views/users/index.html.erb
<h1>Listing users</h1>
 
<table>
  <tr>
    <th>Name</th>
    <th></th>
    <th></th>
    <th></th>
  </tr>
 
<% @users.each do |user| %>
  <tr>
    <td><%= user.name %></td>
    <td><%= link_to 'Show', user %></td>
    <td><%= link_to 'Edit', edit_user_path(user) %></td>
    <td><%= link_to 'Destroy', user, :confirm => 'Are you sure?',
       :method => :delete %></td>
  </tr>
<% end %>
</table>
 
<br />
 
<%= link_to 'New User', new_user_path %>
edit app/views/users/_form.html.erb
<div class="depot_form">
 
<%= form_for @user do |f| %>
  <% if @user.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@user.errors.count, "error") %>
        prohibited this user from being saved:</h2>
      <ul>
      <% @user.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>
 
  <fieldset>
  <legend>Enter User Details</legend>
 
  <div>
    <%= f.label :name %>:
    <%= f.text_field :name, :size => 40 %>
  </div>
 
  <div>
    <%= f.label :password, 'Password' %>:
    <%= f.password_field :password, :size => 40 %>
  </div>
 
  <div>
    <%= f.label :password_confirmation, 'Confirm' %>:
    <%= f.password_field :password_confirmation, :size => 40 %>
  </div>
 
  <div>
    <%= f.submit %>
  </div>
 
  </fieldset>
<% end %>
 
</div>
get /users

Listing users

Name

New User
get /users/new

New user

Enter User Details
:
:
:
Back
post /users
You are being redirected.
get http://localhost:3000/users

Listing users

Name
dave Show Edit Destroy

New User
sqlite3> select * from users
             id = 1
           name = dave
hashed_password = 757d9327b0f3b4c7051880ab07518df812525e7f
           salt = 802780900.796967198069755
     created_at = 2010-06-06 14:39:35.665455
     updated_at = 2010-06-06 14:39:35.665455

13.2 Iteration H2: Authenticating Users 12.8 Iteration J3: Integration Tests