レイアウト変更をテストする
fixture向けのdigestメソッドを追加する
app/models/user.rb
class User < ApplicationRecord
before_save { email.downcase! }
# データベースに保存する前に処理をする。
# 入力されたメールアドレスを小文字にする。
validates :name, presence: true, length: { maximum: 50 }
#属性はname,属性の存在を検証、 最大50字まで
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
#最大255字まで
format: { with: VALID_EMAIL_REGEX },
uniqueness: true
#???
has_secure_password
#セキュアなパスワードの実装
validates :password, presence: true, length: { minimum: 5 }
# パスワードのバリデーションの設定
# 最低は六文字
def User.digest(string)
# 渡された文字列のハッシュ値を返す
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
# fixture用のパスワードを作成します
# stringはハッシュ化する文字列
# costはコストパラメータと呼ばれる値
# ハッシュを算出するための計算コストを指定
end
end
digestメソッドができたので、有効なユーザーを表すfixtureを作成
ユーザーログインのテストで使うfixture
test/fixtures/users.yml
michael:
name: Michael Example
email: michael@example.com
password_digest: <%= User.digest('password') %>
テストユーザー用の有効なパスワードを作成
<%= User.digest('password') %>
password属性を追加すると、そのようなカラムはデータベースに存在しないというエラーが発生する。
有効な情報を使ってユーザーログインをテストする
test/integration/users_login_test.rb
require 'test_helper'
class UsersLoginTest < ActionDispatch::IntegrationTest
def setup
@user = users(:michael)
# ハッシュで呼び出す。
# なんでもハッシュで呼び出せるようになるのか?
end
test "login with valid information" do
get login_path
post login_path, params: { session: { email: @user.email,
password: 'password' } }
assert_redirected_to @user
# リダイレクト先が正しいかどうかをチェック
follow_redirect!
# そのページに実際に移動
# ログインパスのリンクがページにないかどうかで判定
assert_template 'users/show'
assert_select "a[href=?]", login_path, count: 0
# 一回も名前付きルートのloginにいかないことを確認?
assert_select "a[href=?]", logout_path
assert_select "a[href=?]", user_path(@user)
end
end
テスト
ubuntu:~/environment/sample_app (basic-login) $ rails test test/integration/users_login_test.rb
Running via Spring preloader in process 4542
Started with run options --seed 26059
1/1: [==============================] 100% Time: 00:00:03, Time: 00:00:03
Finished in 3.30648s
1 tests, 6 assertions, 0 failures, 0 errors, 0 skips
演習
リスト 8.15の8行目にあるif userから後ろをすべてコメントアウトすると、ユーザー名とパスワードを入力して認証しなくてもテストが通ってしまうことを確認しましょう(リスト 8.26)。通ってしまう理由は、リスト 8.9では「メールアドレスは正しいがパスワードが誤っている」ケースをテストしていないからです。このテストがないのは重大な手抜かりですので、テストスイートで正しいメールアドレスをUsersのログインテストに追加して、この手抜かりを修正してください(リスト 8.27)。テストが red (失敗)することを確認し、それから先ほどの8行目以降のコメントアウトを元に戻すと green (パス)することを確認してください(この演習の修正は重要なので、この先の 8.3のメインのコードにも修正を反映してあります)。
def create
user = User.find_by(email: params[:session][:email].downcase)
# 送信されたメアドを使ってデータベースから取り出す。
#emailを小文字にする
if user # && user.authenticate(params[:session][:password])
# user 取得したユーザーが有効かどうか?
# その後にデータベース上にパスワードがあるか?
# ユーザーログイン後にユーザー情報のページにリダイレクトする
log_in user
# ユーザーのブラウザ内の一時cookiesに暗号化済みのユーザーIDが自動で作成
redirect_to user
# 名前付きルート/userのビューを表示する
else
flash.now[:danger] = 'Invalid email/password combination'
# flash.nowでリクエストが発生後メッセージを消滅する
# エラーメッセージを作成する
render 'new'
# newアクションのビューを表示
end
end
ubuntu:~/environment/sample_app (basic-login) $ rails t
Running via Spring preloader in process 5829
Started with run options --seed 62915
23/23: [============================] 100% Time: 00:00:01, Time: 00:00:01
Finished in 1.98344s
23 tests, 50 assertions, 0 failures, 0 errors, 0 skips
確認されないからかな?
require 'test_helper'
class UsersLoginTest < ActionDispatch::IntegrationTest
def setup
@user = users(:michael)
# ハッシュで呼び出す。
# なんでもハッシュで呼び出せるようになるのか?
end
test "login with valid email/invalid password" do
get login_path
assert_template 'sessions/new'
post login_path, params: { session: { email: @user.email,
password: "invalid" } }
assert_template 'sessions/new'
assert_not flash.empty?
get root_path
assert flash.empty?
end
test "login with valid information" do
get login_path
post login_path, params: { session: { email: @user.email,
password: 'password' } }
assert_redirected_to @user
# リダイレクト先が正しいかどうかをチェック
follow_redirect!
# そのページに実際に移動
# ログインパスのリンクがページにないかどうかで判定
assert_template 'users/show'
assert_select "a[href=?]", login_path, count: 0
# 一回も名前付きルートのloginにいかないことを確認?
assert_select "a[href=?]", logout_path
assert_select "a[href=?]", user_path(@user)
end
end
ubuntu:~/environment/sample_app (basic-login) $ rails t
Running via Spring preloader in process 9430
Started with run options --seed 54106
FAIL["test_login_with_valid_email/invalid_password", #<Minitest::Reporters::Suite:0x0000562f229a1aa8 @name="UsersLoginTest">, 1.4162409589998788]
test_login_with_valid_email/invalid_password#UsersLoginTest (1.42s)
expecting <"sessions/new"> but rendering with <[]>
test/integration/users_login_test.rb:16:in `block in <class:UsersLoginTest>'
24/24: [============================] 100% Time: 00:00:02, Time: 00:00:02
Finished in 2.17638s
24 tests, 52 assertions, 1 failures, 0 errors, 0 skips
ubuntu:~/environment/sample_app (basic-login) $ rails t
Running via Spring preloader in process 9467
Started with run options --seed 21895
24/24: [============================] 100% Time: 00:00:02, Time: 00:00:02
Finished in 2.13073s
24 tests, 54 assertions, 0 failures, 0 errors, 0 skips
一応なったけどわからないなー 。
8.23:ユーザーログインのテストで使うfixtureと書いてあったから。
やってみたけど
“safe navigation演算子”(または“ぼっち演算子”)と呼ばれる&.を用いて、リスト8.15の8行目の論理値(boolean値)のテストを、リスト 8.2812 のようにシンプルに変えてください。Rubyのぼっち演算子を使うと、obj && obj.methodのようなパターンをobj&.methodのように凝縮した形で書けます。変更後も、リスト 8.27のテストがパスすることを確認してください。
def create
user = User.find_by(email: params[:session][:email].downcase)
# 送信されたメアドを使ってデータベースから取り出す。
#emailを小文字にする
if user &.authenticate(params[:session][:password])
# user 取得したユーザーが有効かどうか?
# その後にデータベース上にパスワードがあるか?
# ユーザーログイン後にユーザー情報のページにリダイレクトする
log_in user
# ユーザーのブラウザ内の一時cookiesに暗号化済みのユーザーIDが自動で作成
redirect_to user
# 名前付きルート/userのビューを表示する
else
flash.now[:danger] = 'Invalid email/password combination'
# flash.nowでリクエストが発生後メッセージを消滅する
# エラーメッセージを作成する
render 'new'
# newアクションのビューを表示
end
end