8.6 练习
电子书中有练习的答案,如果想阅读参考答案,请购买电子书。
避免练习和正文冲突的方法参见3.6 节中的说明。
在代码清单 8.32 中,我们定义了生成令牌和摘要的类方法,前面都加上了
User
。这么定义没问题,而且因为我们会使用User.new_token
和User.digest
调用,或许这样定义意思更明确。不过,定义类方法有两种更常用的方式,一种有点让人困惑,一种极其让人困惑。运行测试组件,确认代码清单 8.59(有点让人困惑)和代码清单 8.60(极其让人困惑)中的实现方式是正确的。(注意,在代码清单 8.59 和代码清单 8.60 中,self
是User
类,而用户模型中的其他self
都是用户对象实例。这就是让人困惑的根源所在。)8.4.5 节说过,由于应用现在的设计方式,在代码清单 8.51 的集成测试中无法获取
remember_token
虚拟属性。不过,在测试中使用一个特殊的方法可以获取,这个方法是assigns
。在测试中,可以访问控制器中定义的实例变量,方法是把实例变量的符号形式传给assigns
方法。例如,如果create
动作中定义了@user
变量,在测试中可以使用assigns(:user)
获取这个变量。现在,会话控制器中的create
动作定义了一个普通的变量(不是实例变量),名为user
,如果我们把它改成实例变量,就可以测试cookies
中是否包含用户的记忆令牌。填写代码清单 8.61 和代码清单 8.62 中缺少的内容(?
和FILL_IN
),完成改进后的“记住我”复选框测试。
代码清单 8.59:使用 self
定义生成令牌和摘要的方法 GREEN
app/models/user.rb
class User < ActiveRecord::Base
.
.
.
# 返回指定字符串的哈希摘要
def self.digest(string) cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
# 返回一个随机令牌
def self.new_token SecureRandom.urlsafe_base64
end
.
.
.
end
代码清单 8.60:使用 class << self
定义生成令牌和摘要的方法 GREEN
app/models/user.rb
class User < ActiveRecord::Base
.
.
.
class << self # 返回指定字符串的哈希摘要
def digest(string) cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
# 返回一个随机令牌
def new_token SecureRandom.urlsafe_base64
end
end
.
.
.
代码清单 8.61:在 create
动作中使用实例变量的模板
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
代码清单 8.62:改进后的“记住我”复选框测试模板 GREEN
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 assigns(:user).FILL_IN, FILL_IN end
test "login without remembering" do
log_in_as(@user, remember_me: '0')
assert_nil cookies['remember_token']
end
.
.
.
end