###二つの目立たないバグ
ユーザーがログイン中の場合にのみログアウトさせる必要がある。
、ユーザーが複数のブラウザ(FirefoxやChromeなど)でログインしていたときに起こります
####2番目のウィンドウでユーザーをログアウトするテスト
test/integration/users_login_test.rb
require 'test_helper'
class UsersLoginTest < ActionDispatch::IntegrationTest
def setup
@user = users(:michael)
# ハッシュで呼び出す。
# なんでもハッシュで呼び出せるようになるのか?
end
.
.
.
test "login with valid information followed by logout" do
get login_path
# ログイン画面にいく
post login_path, params: { session: { email: @user.email,
password: 'password' } }
# データをデータベースに投稿
assert is_logged_in?
# ログインされているよね?
assert_redirected_to @user
# ユーザー情報を取り出すのか?
follow_redirect!
# もう一回確認
assert_template 'users/show'
# ユーザーページに移動する
assert_select "a[href=?]", login_path, count: 0
assert_select "a[href=?]", logout_path
assert_select "a[href=?]", user_path(@user)
delete logout_path
assert_not is_logged_in?
assert_redirected_to root_url
# 2番目のウィンドウでログアウトをクリックするユーザーをシミュレートする
delete logout_path
follow_redirect!
assert_select "a[href=?]", login_path
# これは表示する
assert_select "a[href=?]", logout_path, count: 0
assert_select "a[href=?]", user_path(@user), count: 0
# 上2行は非表示になっていることを確認。
end
end
delete logout_path
を書くことによって二度目のログアウトを試すことができることがわかった。
#####テスト
ubuntu:~/environment/sample_app (advanced-login) $ rails t
Running via Spring preloader in process 8268
Started with run options --seed 30959
ERROR["test_login_with_valid_information_followed_by_logout", #<Minitest::Reporters::Suite:0x0000555ef3ce2c08 @name="UsersLoginTest">, 5.425516088000222]
test_login_with_valid_information_followed_by_logout#UsersLoginTest (5.43s)
NoMethodError: NoMethodError: undefined method `forget' for nil:NilClass
app/helpers/sessions_helper.rb:58:in `forget'
app/helpers/sessions_helper.rb:67:in `log_out'
app/controllers/sessions_controller.rb:32:in `destroy'
test/integration/users_login_test.rb:44:in `block in <class:UsersLoginTest>'
24/24: [============================] 100% Time: 00:00:05, Time: 00:00:05
Finished in 5.96672s
24 tests, 58 assertions, 0 failures, 1 errors, 0 skips
NoMethodError: undefined method `forget' for nil:NilClass
NoMethodError:
「メソッドがない」という意味
undefined method `forget' for nil:NilClass
nilクラスになっているためforgetメソッドが見つからないのかな?
####ログイン中の場合のみログアウトする
app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
.
.
.
def destroy
# ユーザー削除
log_out if logged_in?
# log_outメソッドを発動 もしログインされてたら
redirect_to root_url
# ホーム画面に戻る
end
end
#####テスト
ubuntu:~/environment/sample_app (advanced-login) $ rails t
Running via Spring preloader in process 4083
Started with run options --seed 36998
24/24: [============================] 100% Time: 00:00:03, Time: 00:00:03
Finished in 3.43251s
24 tests, 61 assertions, 0 failures, 0 errors, 0 skips
上のコードで条件をつけることによってログアウトできるようにしたみたい。
####ダイジェストが存在しない場合のauthenticated?のテスト
test/models/user_test.rb
require 'test_helper'
class UserTest < ActiveSupport::TestCase
.
.
.
test "authenticated? should return false for a user with nil digest" do
assert_not @user.authenticated?('')
# 記憶ダイジェストはからじゃないよね?
end
end
#####テスト
ubuntu:~/environment/sample_app (advanced-login) $ rails t
Running via Spring preloader in process 4630
Started with run options --seed 26378
ERROR["test_authenticated?_should_return_false_for_a_user_with_nil_digest", #<Minitest::Reporters::Suite:0x00007fd9c14daa60 @name="UserTest">, 2.703540293999822]
test_authenticated?_should_return_false_for_a_user_with_nil_digest#UserTest (2.70s)
BCrypt::Errors::InvalidHash: BCrypt::Errors::InvalidHash: invalid hash
app/models/user.rb:49:in `new'
app/models/user.rb:49:in `authenticated?'
test/models/user_test.rb:88:in `block in <class:UserTest>'
25/25: [============================] 100% Time: 00:00:03, Time: 00:00:03
Finished in 3.43387s
25 tests, 61 assertions, 0 failures, 1 errors, 0 skips
BCrypt::Errors::InvalidHash: BCrypt::Errors::InvalidHash: invalid hash
無効なハッシュがあるからエラーになるのかな?
####authenticated?を更新して、ダイジェストが存在しない場合に対応
app/models/user.rb
class User < ApplicationRecord
.
.
.
# 渡されたトークンがダイジェストと一致したらtrueを返す
def authenticated?(remember_token)
return false if remember_digest.nil?
# 記憶ダイジェストが空の場合 falseを返すことができる
BCrypt::Password.new(remember_digest).is_password?(remember_token)
# remember_tokenとremamber_digestを比較するもの
# bycryptで暗号化
# .is_password?で==の働きをする
end
# ユーザーのログイン情報を破棄する
def forget
# ユーザーがログアウトできるようにするため
update_attribute(:remember_digest, nil)
# .forgetで.rememberが取り消される
# nilに更新される
end
end
#####テスト
ubuntu:~/environment/sample_app (advanced-login) $ rails t
Running via Spring preloader in process 4973
Started with run options --seed 52742
25/25: [============================] 100% Time: 00:00:02, Time: 00:00:02
Finished in 2.38406s
25 tests, 62 assertions, 0 failures, 0 errors, 0 skips
###演習
1.
リスト 9.16で修正した行をコメントアウトし、2つのログイン済みのタブによるバグを実際に確かめてみましょう。まず片方のタブでログアウトし、その後、もう1つのタブで再度ログアウトを試してみてください。
コメントアウト後accountが消えなかった。 修正後消えた。
リスト 9.19で修正した行をコメントアウトし、2つのログイン済みのブラウザによるバグを実際に確かめてみましょう。まず片方のブラウザでログアウトし、もう一方のブラウザを再起動してサンプルアプリケーションにアクセスしてみてください。
できなかった。
上のコードでコメントアウトした部分を元に戻し、テストスイートが red から green になることを確認しましょう。
buntu:~/environment/sample_app (advanced-login) $ rails t
Running via Spring preloader in process 8142
Started with run options --seed 10285
ERROR["test_authenticated?_should_return_false_for_a_user_with_nil_digest", #<Minitest::Reporters::Suite:0x000055d781f9bba0 @name="UserTest">, 5.757596166999974]
test_authenticated?_should_return_false_for_a_user_with_nil_digest#UserTest (5.76s)
BCrypt::Errors::InvalidHash: BCrypt::Errors::InvalidHash: invalid hash
app/models/user.rb:51:in `new'
app/models/user.rb:51:in `authenticated?'
test/models/user_test.rb:88:in `block in <class:UserTest>'
FAIL["test_login_with_valid_information_followed_by_logout", #<Minitest::Reporters::Suite:0x000055d781e67db0 @name="UsersLoginTest">, 6.913151000999733]
test_login_with_valid_information_followed_by_logout#UsersLoginTest (6.91s)
Expected true to be nil or false
test/integration/users_login_test.rb:41:in `block in <class:UsersLoginTest>'
25/25: [============================] 100% Time: 00:00:07, Time: 00:00:07
Finished in 7.02619s
25 tests, 57 assertions, 1 failures, 1 errors, 0 skips
BCrypt::Errors::InvalidHash: BCrypt::Errors::InvalidHash: invalid hash
ダイジェストが無効になっているためかな?
Expected true to be nil or false
記憶ダイジェストが空になっていない。
多分ブラウザが違うとログイン状態になったままなのかな?