Ruby on Rails實戰–創建一個網上商店E用戶管理模塊

本節創建商店的用戶管理系統. 創建存放用戶資料的數據表,加入添加,刪除用戶功能, 後台管理用戶權限審查功能,和用戶登錄 退出功能.
創建用戶model: depot> ruby script/generate model user
修改depot/db/migrate/007_create_users.rb文件內容如下:
class CreateUsers < ActiveRecord::Migration
  def self.up
    create_table :users do |t|
      t.column :name, :string
      t.column :hashed_password, :string
      t.column :salt, :string #生成密碼hash用的salt
    end
  end

 
  def self.down
    drop_table :users
  end
end

應用depot> rake db:migrate

修改depot/app/models/user.rb文件內容如下:
require ‘digest/sha1′
#用來生成密碼hash值
class User < ActiveRecord::Base

#檢驗添加用戶表格
  validates_presence_of :name,
  :password,
  :password_confirmation
  validates_uniqueness_of :name
  validates_length_of :password,
  :minimum => 5,
  :message => "should be at least 5 characters long"
  attr_accessor :password_confirmation
  #自動"再輸入一次密碼"的檢驗
  validates_confirmation_of :password
 
  # ‘password’ 是一個 virtual attribute
  def password
    @password
  end
 
  def password=(pwd)
    @password = pwd
    create_new_salt
    self.hashed_password = User.encrypted_password(self.password, self.salt)
  end
 
  def self.authenticate(name, password)
    user = self.find_by_name(name)
    if user
      expected_password = encrypted_password(password, user.salt)
      if user.hashed_password != expected_password
        user = nil
      end
    end
    user
  end
 
  #安全刪除,當試圖刪除用戶表中最後一個用戶時rollback數據庫內容
  def safe_delete
    transaction do
      destroy
      if User.count.zero?
        raise "Can’t delete last user"
      end
    end
  end
 
  private
 
  def self.encrypted_password(password, salt)
    string_to_hash = password + "wibble" + salt
    Digest::SHA1.hexdigest(string_to_hash)
  end
 
  def create_new_salt
    self.salt = self.object_id.to_s + rand.to_s
  end
end

生成Login controller
depot> ruby script/generate controller Login add_user login logout delete_user list_users
後面接的大堆都是login裡面的actions.
depot/app/controllers/login_controller.rb文件內容為:
class LoginController < ApplicationController
  #所有actions,除了login都要進行權限審查
  before_filter :authorize, :except => :login
  #加入admin的模板
  layout"admin"
 
  def index
    @total_orders = Order.count
  end
 
  def add_user
    @user = User.new(params[:user])
    if request.post? and @user.save
 #requset.post?用來檢驗request是否POST形式
      flash[:notice] = "User #{@user.name} created"
      @user = User.new
    end
  end
 
  def login
    session[:user_id] = nil
    if request.post?
      user = User.authenticate(params[:name], params[:password])
      if user
        session[:user_id] = user.id
        #如果原來頁面存在,返回原先頁面
        redirect_to(session[:original_url] || { :action => "index" })
      else
        flash[:notice] = "Invalid user/password combination"
      end
    end
  end
 
  def logout
    session[:user_id] = nil
    flash[:notice] = "Logged out"
    redirect_to(:action => "login")
  end
 
  def delete_user
    id = params[:id]
    if id && user = User.find(id)
      begin
   #安全刪除
        user.safe_delete
        flash[:notice] = "User #{user.name} deleted"
      rescue Exception => e
        flash[:notice] = e.message
      end
    end
    redirect_to(:action => :list_users)
  end
 
  def list_users
    @all_users = User.find(:all)
  end
end

修改depot/app/controllers/application.rb文件,添加用戶權限審查代碼:
class ApplicationController < ActionController::Base
  private
  def authorize
    unless User.find_by_id(session[:user_id])
      session[:original_uri] = request.request_uri #記住原來頁面
      flash[:notice] = "Please log in"
      redirect_to(:controller => "login", :action => "login")
    end
  end
end

向depot/app/controllers/admin_controller.rb文件加入審查要求:
class AdminController < ApplicationController
  before_filter :authorize

  #….

修改管理頁面使用的頁面模板depot/app/views/layouts/admin.rhtml,內容如下:
<html>
 <head>
  <title>Administer the Bookstore</title>
  <%= stylesheet_link_tag "scaffold", "depot", :media => "all" %>
 </head>
 <body id="admin">
  <div id="banner">
   <img src="/images/logo.png"/>
   <%= @page_title || "Pragmatic Bookshelf" %>
  </div>
  <div id="columns">
   <div id="side">
    <p>
     <%= link_to "Products", :controller => ‘admin’, :action => ‘list’ %>
    </p>
    <p>
     <%= link_to "List users", :controller => ‘login’, :action => ‘list_users’ %>
     <br/>
     <%= link_to "Add user", :controller => ‘login’, :action => ‘add_user’ %>
    </p>
    <p>
     <%= link_to "Logout", :controller => ‘login’, :action => ‘logout’ %>
    </p>
   </div>
   <div id="main">
    <% if flash[:notice] -%>
     <div id="notice"><%= flash[:notice] %></div>
    <% end -%>
    <%= @content_for_layout %>
   </div>
  </div>
 </body>
</html>

添加用戶頁面depot/app/views/login/add_user.rhtml內容:
<div class="depot-form">
 <%= error_messages_for ‘user’ %>
 <fieldset>
  <legend>Enter User Details</legend>
  <% form_for :user do |form| %>
   <p>
    <label for="user_name">Name:</label>
    <%= form.text_field :name, :size => 40 %>
    <!–上面代碼自動生成input框–>
   </p>
   <p>
    <label for="user_password">Password:</label>
    <%= form.password_field :password, :size => 40 %>
   </p>
   <p>
    <label for="user_password_confirmation">Confirm:</label>
    <%= form.password_field :password_confirmation, :size => 40 %>
   </p>
   <%= submit_tag "Add User", :class => "submit" %>
  <% end %>
 </fieldset>
</div>

用戶登錄頁面depot/app/views/login/login.rhtml內容為:
<div class="depot-form">
 <fieldset>
  <legend>Please Log In</legend>
  <%= start_form_tag %>
  <!–form開始–>
   <p>
    <label for="name">Name:</label>
    <%= text_field_tag :name, params[:name] %>
   </p>
   <p>
    <label for="password">Password:</label>
    <%= password_field_tag :password, params[:password] %>
   </p>
   <p>
    <%= submit_tag "Login" %>
   </p>
  <%= end_form_tag %>
 </fieldset>
</div>

用戶主頁depot/app/views/login/index.rhtml內容:
<h1>Welcome</h1>
It’s <%= Time.now %>.
We have <%= pluralize(@total_orders,"order") %>.
<!–pluralize自動根據@total_orders的數量決定order使用單數還是複數形式–>

用戶列表頁面depot/app/views/login/list_users.rhtml內容:
<h1>Administrators</h1>
<ul>
 <%  for user in @all_users %>
  <li><%= link_to "[X]", { # link_to 參數
  #在用戶名前自動添加刪除用戶的鏈接
  :controller => ‘login’,
  :action => ‘delete_user’,
  :id => user},
  { # html 參數
  :post => true,
  :confirm => "Really delete #{user.name}?"
  } %>
  <%= user.name %>
  </li>
 <% end %>
</ul>

整理代碼:
在depot/app/controllers/store_controller.rb中加入:
  before_filter :find_cart, :except => :empty_cart
  def find_cart
    @cart = (session[:cart] ||= Cart.new)
  end
並刪除其它散雜的@cart賦值語句.

本節結束.

此條目發表在 Ruby on Rails 分類目錄。將固定鏈接加入收藏夾。

發表評論