on Rails : login_generatorを本格的に使ってみる2
[Ruby]on Rails : login_generatorを本格的に使ってみる1の続きです.コッチは比較的ソース多めなので,勘弁してください.
モデルのテスト
それでは,先ずはテスト用のtest/fixture/users.ymlを弄ります.ユーザ名を追加したので,ちゃんとfixtureにも追加します.
izumi: id: 1 name : 泉野明 login: izumi password: <%= User.sha1("test1") %> asuma: id: 2 name : 篠原遊馬 login: asuma password: <%= User.sha1("test2") %> isao: id: 3 name : 太田功 login: isao password: <%= User.sha1("test3") %>
次に,テストケースも弄ります.まずはモデルUserのテストケースから.test/unit/user_test.rbを開き,編集.折角ですから,ユーザ名が入力されていなかったときのテストケースも先に作っちゃいましょう.ひとつだけ,例を載せます.
def test_disallowed_passwords u = User.new u.login = "gotou" u.name = "後藤喜一" u.password = u.password_confirmation = "tiny" assert !u.save assert u.errors.invalid?('password') u.password = u.password_confirmation = "huge" * 100 assert !u.save assert u.errors.invalid?('password') u.password = u.password_confirmation = "" assert !u.save assert u.errors.invalid?('password') u.password = u.password_confirmation = "secure_password" assert u.save assert u.errors.empty? end
ちゃんとtest_createやtest_bad_password,test_bad_loginにもu.nameを書き,適当に作れたら,モデルだけのテストを行う.
$ rake test:units
さて,test_bad_namesの部分でエラーが出たはずですから,次はモデルの修正をします.
validates_length_of :name, :within => 4 .. 40 # 追加 validates_presence_of :login, :password, :password_confirmation, :name # :nameを追加
こうするだけ.もう一度rake test:unitsをすると,通ります.
全体のテスト
次は普通にrakeを実行してみます.すると,やたらとassert_session_hasで,セッションにuserなんてねーよって怒られるはず.ちなみに,test_auth_bobとかいうのはtest_loginみたいなもんだから,こんなワケの分からん名前は変えましょう.とりあえず,テストケースはこうなりました.
require File.dirname(__FILE__) + '/../test_helper' require 'account_controller' # Raise errors beyond the default web-based presentation class AccountController; def rescue_action(e) raise e end; end class AccountControllerTest < Test::Unit::TestCase self.use_instantiated_fixtures = true #忘れずに! fixtures :users def setup @controller = AccountController.new @request, @response = ActionController::TestRequest.new, ActionController::TestResponse.new @request.host = "localhost" end def test_login post :login, :user => {:login => "asuma", :password => "test2"} assert_session_has :user assert_equal @asuma, @response.session[:user] assert_redirected_to :action => "welcome" end def test_signup post(:signup, :user => { :name => "熊耳武緒", :login => "takeo", :password => "newpassword", :password_confirmation => "newpassword" }) assert_session_has :user assert_redirected_to :action => "welcome" end def test_bad_signup post :signup, :user => { :name => "新ボブ", :login => "newbob", :password => "newpassword", :password_confirmation => "wrong" } assert_invalid_column_on_record "user", "password" assert_success post :signup, :user => { :name => "よ", "login" => "yo", :password => "newpassword", :password_confirmation => "newpassword" } assert_invalid_column_on_record "user", "login" assert_success post :signup, :user => { :name => "よよよ", :login => "yo", :password => "newpassword", :password_confirmation => "wrong" } assert_invalid_column_on_record "user", ["login", "password"] assert_success end def test_invalid_login post :login, :user => {:login => "izumi", :password => "machigai"} assert_session_has_no :user end def test_login_logoff post :login, :user => {:login => "izumi", :password => "test1"} assert_session_has :user get :logout assert_session_has_no :user end end
rakeを実行すると,先ず間違いなく失敗すると思います.
ビューを直そう
次に,ビューを弄ります.弄らなければ行けないのは,singupとloginだけ.まずはsignup.rhtmlから.
<%= start_form_tag :action=> "signup" %> <div title="Account signup" id="signupform" class="form"> <h3>サインアップ</h3> <%= error_messages_for 'user' %><br/> <label for="user_name">お名前:</label><br/> <%= text_field "user", "name", :size => 30 %><br /> <label for="user_login">ご希望のログインネーム:</label><br/> <%= text_field "user", "login", :size => 30 %><br/> <label for="user_password">パスワード:</label><br/> <%= password_field "user", "password", :size => 30 %><br/> <label for="user_password_confirmation">パスワード確認:</label><br/> <%= password_field "user", "password_confirmation", :size => 30 %><br/> <%= submit_tag 'サインイン' %> <%= end_form_tag %>
名前入力欄を追加しました.
つぎにlogin.rhtmlを.
<%= start_form_tag :action=> "login" %> <div title="Account login" id="loginform" class="form"> <h3>ログインしてください</h3> <% if @message %> <div id="message"><%= @message %></div> <% end %> <p><label for="user_login">ログイン:</label><br/> <%= text_field 'user', 'login' %></p> <p><label for="user_password">パスワード:</label><br/> <%= password_field 'user', 'password' %></p> <%= submit_tag 'ログイン' %> <br/> </div> <%= end_form_tag %>
パラメータを@param[:user][:login]みたいな形にしたかったので,こうしました.こうするとコントローラからも取り易いし,わかり易いし.
コントローラも直そう
最後に,コントローラの編集.
class AccountController < ApplicationController model :user layout 'scaffold' def login case @request.method when :post if @session[:user] = User.authenticate(@params[:user][:login], @params[:user][:password]) flash[:notice] = "Login successful" redirect_to :action => "welcome" else @login = @params[:login] @message = "Login unsuccessful" end end end def signup case @request.method when :post @user = User.new(@params[:user]) if @user.save @session[:user] = User.authenticate(@user.login, @params[:user][:password]) flash[:notice] = "Signup successful" redirect_to :action => "welcome" end when :get @user = User.new end end def delete if @params[:id] @user = User.find(@params[:id]) @user.destroy end redirect_to :action => "welcome" end def logout @session[:user] = nil end def welcome end end
いきなりdeleteとか出来てますが,ここは気にしちゃ駄目だと思うぜ.俗に言う親切心ってやつだもんな.
さて,これで出来上がり.rakeをしてみると通ります.
以上で,ごく簡単なlogin_generatorの使い方を終わらせてもらいます.
総括
確かに自動でログイン周りを作ってくれるのは,とても有り難いことだ.しかし,テストケースが始めからできているというのも困った話で,テストケースに関しては,ほとんど一から自分で書くのと変わらないぐらいの労力が必要な気もする.全体を通してみると,楽なのは楽,なのかな?