Ruby on Rails ショッピングカート part8 ユーザ管理

Ruby on Rails において ショッピングカート とは以下を示します。

  1. テーブル作成
     下記のテーブルを作成する。
    
    1. create.sql
       create table users (
         id              int           not null auto_increment,
         name            varchar(100)  not null,
         hashed_password char(40)      null,
         primary key (id)
       );
      
  2. モデル作成
     %cd depot
     %ruby script/generate model User
           exists  app/models/
           exists  test/unit/
           exists  test/fixtures/
           create  app/models/user.rb
           create  test/unit/user_test.rb
           create  test/fixtures/users.yml
           exists  db/migrate
           create  db/migrate/003_create_users.rb
    
  3. コントローラー作成(名前=Login)
     ここでは、scaffoldジェネレータを使用せずに手動でコント
     ローラー、メソッドを作成したいと思う。
    
    • それは、ユーザ管理機能用のジェネレータが存在するらしいから。
     %ruby script/generate controller Login add_user login logout
           exists  app/controllers/
           exists  app/helpers/
           create  app/views/login
           exists  test/functional/
           create  app/controllers/login_controller.rb
           create  test/functional/login_controller_test.rb
           create  app/helpers/login_helper.rb
           create  app/views/login/add_user.rhtml
           create  app/views/login/login.rhtml
           create  app/views/login/logout.rhtml
    
  4. メソッド実装
     今までは、new()、create()、のように2つのメソッドで
     DBに格納していました。
     (edit()、update()、も同じような感じですね。)
    
    • しかし、今回は1つのメソッドで実装してみたいと思います。
        つまり、初期フォームを表示するのか、フォームのデータを保存
        するのか、判別する意味です。この判別には、HTTPメソッドの種類で
        判別する。
      
        GET:データを持たないリクエスト
        POST:フォームデータを含むリクエスト
      
    1. /app/controllers/login_controller.rb
       class LoginController < ApplicationController
         layout "admin"
      
         def add_user
           if request.get?
             @user = User.new
           else
             @user = User.new(params[:user])
             if @user.save
               redirect_to_index("ユーザ #{@user.name} が作成されました")
             end
           end
         end
      
         def login
         end
      
         def logout
         end
       end
      
  5. ビュー実装
     ビューを編集する。
    
    • form_tag
        アクションを何も指定しない場合には、デフォルトで、
        同じコントローラ内の、そのテンプレートをレンダリングした
        アクションに送り返される。
        だから、ここではadd_user()メソッドに行く。
      
    1. /app/views/login/add_user.rhtml
       <% @page_title = "ユーザの追加" -%>
       <%= error_messages_for 'user' %>
      
       <%= form_tag %>
       <table>
         <tr>
           <td>ユーザ名:</td>
           <td><%= text_field("user", "name") %></td>
         </tr>
         <tr>
           <td>パスワード:</td>
           <td><%= password_field("user", "password") %></td>
         </tr>
      
         <tr>
           <td></td>
           <td><input type="submit" value=" ユーザを追加 " /></td>
         </tr>
       </table>
       <% end_form_tag %>
      
  6. 実行
     とりあえず実行してみたけど、これだけでは格納できない!!
    
    1. /log/production.log
       Processing LoginController#add_user
       (for 124.102.28.37 at 2007-02-08 19:20:08) [GET]
         Session ID: 14b8ef7c4be61526eaa7cbe662c603a5
         Parameters: {"action"=>"add_user", "controller"=>"login"}
       Rendering  within layouts/admin
       Rendering login/add_user
      
       ActionView::TemplateError
       (undefined method `password' for #<User:0x8e3dd64>)
       on line #12 of app/views/login/add_user.rhtml:
       9:   </tr>
       10:   <tr>
       11:     <td>繝代せ繝ッ繝シ繝・</td>
       12:     <td><%= password_field("user", "password") %></td>
       13:   </tr>
       14:
       15:   <tr>
      
  7. hashed_password属性
     usersテーブルは、hashed_password属性を持っている。
     なので、UsersクラスはActiveRecordモデルなので上記の
     事を認識している!!(頭良いね)
    
     つまり、データベースには平文のパスワードは格納されないので、
     モデル内にはそれに対応する
     属性は存在しない。だから、モデル内に読み書き可能な属性を作成する。
    
    1. /app/models/user.rb
       class User < ActiveRecord::Base
         attr_accessor :password
       end
      
  8. 実行
     これではどうだ!?
    
    • http://www.bishounen.sakura.ne.jp/rails/images/knowledge/151_01_attr_accessor.jpg
  9. この状態でDBにユーザ登録
     試しにユーザ登録してみた。
     add_user.rhtmlが表示されるかと思いきや・・・・・
    
    • http://www.bishounen.sakura.ne.jp/rails/images/knowledge/151_02_404.jpg
    1. /log/production.log
       Processing LoginController#add_user
       (for 124.102.28.37 at 2007-02-08 19:33:47) [POST]
         Session ID: 14b8ef7c4be61526eaa7cbe662c603a5
         Parameters: {"user"=>{"name"=>"admin", "password"=>"admin"},
         "action"=>"add_user", "controller"=>"login"}
       Redirected to http://www.bishounen.sakura.ne.jp/rails_depot/login
       Completed in 0.07647 (13 reqs/sec) | DB: 0.03837 (50%) |
       302 Found [http://www.bishounen.sakura.ne.jp/rails_depot/login/add_user]
      
       Processing LoginController#index
       (for 124.102.28.37 at 2007-02-08 19:33:47) [GET]
         Session ID: 14b8ef7c4be61526eaa7cbe662c603a5
         Parameters: {"action"=>"index", "controller"=>"login"}
      
       ActionController::UnknownAction (No action responded to index):
      
    • でもDBには登録されているんだね。
        そりゃそうだよ!!DBの列名は"hash_password"だから登録されないのは当たり前!!
      
    • http://www.bishounen.sakura.ne.jp/rails/images/knowledge/151_03_404_db.jpg
  10. コールバックフック
     Active Recordでは、様々なコールバックフックが用意されている。
     そのコールバックのタイミングは、モデルが検証される前、データが
     データベースに保存される前、行が作成された後、などある。
    
    1. before_create()
       データベースの行として保存される前の時点
      
    2. after_create()
       行が保存された後
      
    • 平文のパスワード
        セッションデータに平文のパスワードが残っていたら危険なので、
        DBに保存した後にフィールドをクリアする。
      
  11. クラスメソッド編集
     パスワードのハッシュ化、DB格納後のパスワードフィールドのクリア
     などを記述。
    
    • attr_accessible
        指定された属性以外の属性が、フォームからの入力によって自動的に設定
        されないようにする。ここでは、「:name、:password」だけだよ!!って設定している。
      
    1. /app/models/user.rb
       require "digest/sha1"
       class User < ActiveRecord::Base
      
         attr_accessor :password
         attr_accessible :name, :password
      
         validates_uniqueness_of :name
         validates_presence_of   :name, :password
      
         def before_create
           self.hashed_password = User.hash_password(self.password)
         end
      
         def after_create
           @password = nil
         end
      
         private
      
         def self.hash_password(password)
           Digest::SHA1.hexdigest(password)
         end
       end
      
  12. 実行
     index.rhtmlの存在が気になるが・・・・・実行してみる。
     やはり画面はこんな感じでダメ。
    
    • http://www.bishounen.sakura.ne.jp/rails/images/knowledge/151_02_404.jpg
     確かにハッシュ化されている。さすが!!
    
    • http://www.bishounen.sakura.ne.jp/rails/images/knowledge/151_04_404_db.jpg
     しかし、ログファイルには平文で出力されているけど・・・・・これは良いの??
    
    1. /log/production.log
       Processing LoginController#add_user
       (for 124.102.37.145 at 2007-02-08 21:47:29) [POST]
         Session ID: 5f46660e9b92cc4993ae47de936ece2d
         Parameters: {"user"=>{"name"=>"stark", "password"=>"stark"},
         "action"=>"add_user", "controller"=>"login"}
       Redirected to http://www.bishounen.sakura.ne.jp/rails_depot/login
       Completed in 0.05545 (18 reqs/sec) | DB: 0.01928 (34%) |
       302 Found [http://www.bishounen.sakura.ne.jp/rails_depot/login/add_user]
      
  13. index()メソッド、ビュー作成
     404画面に遷移するのは気持ち悪い。
     だから、リダイレクト先のindex()メソッド、ビューを作成してみた。
    
    1. /app/controllers/login_controller.rb
       def index
       end
      
    2. /app/views/login/index.rhtml
       <%  @page_title = "Administer your Store" -%>
      
       <h1>Depot Store Status</h1>
      
    • http://www.bishounen.sakura.ne.jp/rails/images/knowledge/151_05_index_add.jpg

ご訪問頂き有難う御座います。 当サイトを効率良く使うためにまずは FrontPage を見て下さい。 検索方法、一覧表示などの各情報を纏めています。
当サイトの説明 → Frontpage