Exercises
在 app/models/user.rb 中,我們定義了產生 token 和 digest 的 class method:
# Returns the hash digest of the given string.
def User.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
# Returns a random token.
def User.new_token
SecureRandom.urlsafe_base64
end
這樣定義很明確,表示我們會使用 User.digest 和 User.new_token 調用。不過定義 class method 還有兩種常用的方法,可能會讓人有點困惑。
執行測試,確認下面兩種寫法都會通過測試:
app/models/user.rb
class User < ActiveRecord::Base
.
.
.
# Returns the hash digest of the given string.
def self.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
# Returns a random token.
def self.new_token
SecureRandom.urlsafe_base64
end
.
.
.
end
class User < ActiveRecord::Base
.
.
.
class << self
# Returns the hash digest of the given string.
def digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
# Returns a random token.
def new_token
SecureRandom.urlsafe_base64
end
end
.
.
.
注意在上述程式碼中的 self 是代表 User class,在 User model 中其他的 self 是表示 user 實例物件。
之前提過,由於 APP 的設計方式,在 test/integration/users_login_test.rb 整合測試中,無法使用 remember_token 虛擬屬性。不過其實可以透過在測試中使用 assigns 方法來取得。
在測試中可以使用 assigns 方法來取得在 controller 裡定義的實例變數,做法是把實例變數的 symbol 形式傳給 assigns 方法。例如,如果在 create action 定義了 @user 變數,在測試中就可以透過 assigns(:user) 的形式取得這個實例變數。
目前在 Sessions controller 裡面的 create action 定義了一個普通的變數 user (非實例變數),如果我們把它改成實例變數,就可以測試 cookies 是否包含使用者的 remember token。
在下面兩個程式碼中,完成缺少的部分(? 和 FILL_IN),進而能完善 remember me 的 checkbox 測試:
app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
def new
end
def create
?user = User.find_by(email: params[:session][:email].downcase)
if ?user && ?user.authenticate(params[:session][:password])
log_in ?user
params[:session][:remember_me] == '1' ? remember(?user) : forget(?user)
redirect_to ?user
else
flash.now[:danger] = 'Invalid email/password combination'
render 'new'
end
end
def destroy
log_out if logged_in?
redirect_to root_url
end
end
test/integration/users_login_test.rb
require 'test_helper'
class UsersLoginTest < ActionDispatch::IntegrationTest
def setup
@user = users(:michael)
end
.
.
.
test "login with remembering" do
log_in_as(@user, remember_me: '1')
assert_equal FILL_IN, assigns(:user).FILL_IN
end
test "login without remembering" do
log_in_as(@user, remember_me: '0')
assert_nil cookies['remember_token']
end
.
.
.
end