Rails教程账户激活测试失败问题求助
嘿,咱们来搞定这个测试失败的问题!我最近跟着在线Rails教程学习时,碰到了一模一样的账户激活测试失败情况,具体错误和相关代码如下:
测试失败报错信息
FAIL["test_valid_signup_information_with_account_activation", UsersSignupTest, 5.62457 6674999844] test_valid_signup_information_with_account_activation#UsersSignupTest (5.63s) Expected false to be truthy. test/integration/users_signup_test.rb:38:in block in <class:UsersSignupTest>
测试文件代码(test/integration/users_signup_test.rb)
require 'test_helper' class UsersSignupTest < ActionDispatch::IntegrationTest def setup ActionMailer::Base.deliveries.clear end test "invalid signup information" do get signup_path assert_no_difference 'User.count' do post users_path, params: { user: { name: "", email: "user@invalid", password: "foo", password_confirmation: "bar" } } end assert_template 'users/new' assert_select 'div#error_explanation' assert_select 'div.field_with_errors' end test "valid signup information with account activation" do get signup_path assert_difference 'User.count', 1 do post users_path, params: { user: { name: "Example User", email: "user@example.com", password: "foobar12", password_confirmation: "foobar12" } } end assert_equal 1, ActionMailer::Base.deliveries.size user = assigns(:user) assert_not user.activated? # 尝试在激活前登录 log_in_as(user) assert_not is_logged_in? # 无效的激活令牌 get edit_account_activation_path("invalid token") assert_not is_logged_in? # 有效令牌,但邮箱错误 get edit_account_activation_path(user.activation_token, email: 'wrong') assert_not is_logged_in? # 有效激活令牌 get edit_account_activation_path(user.activation_token, email: user.email) assert user.reload.activated? # 👉 问题就出在这一行,预期激活为true但实际是false follow_redirect! assert_template 'users/show' assert is_logged_in? end end
账户激活控制器代码(app/controllers/account_activations_controller.rb)
class AccountActivationsController < ApplicationController def edit user = User.find_by(email: params[:email]) if user && !user.activated? && user.authenticated?(:activation, params[:id]) # user.activate # 这里被注释掉了,是不是问题所在? user.update_attribute(:activated, true) user.update_attribute(:activated_at, Time.zone.now) log_in user flash[:success] = "Account activated!" redirect_to user else flash[:danger] = "Invalid activation link" redirect_to root_url end end end
问题排查与修复思路
我当时碰到这个问题时,主要从这几个方向排查,你可以逐一检查:
1. 确认控制器激活逻辑是否执行
先判断请求edit_account_activation_path时,控制器里的激活代码块(if分支内的代码)是否真的被触发。你可以临时加调试输出验证:
def edit user = User.find_by(email: params[:email]) puts "找到的用户:#{user.inspect}" puts "用户未激活?#{!user.activated?}" if user puts "令牌验证通过?#{user.authenticated?(:activation, params[:id])}" if user if user && !user.activated? && user.authenticated?(:activation, params[:id]) # ... 原有代码 puts "激活代码执行了!" else puts "进入错误分支了!" end end
运行测试后看终端输出,就能知道是否进入了正确的分支。
2. 验证authenticated?方法正确性
User模型里的authenticated?方法必须正确处理:activation类型,标准实现应该是这样的:
def authenticated?(attribute, token) digest = send("#{attribute}_digest") return false if digest.nil? BCrypt::Password.new(digest).is_password?(token) end
如果方法参数顺序错误、未正确调用activation_digest,会导致令牌验证失败,跳过激活逻辑。
3. 检查用户创建时的激活字段初始化
用户创建时,必须通过回调生成activation_token和activation_digest,并默认设置activated: false。你的User模型应该包含以下代码:
before_create :create_activation_digest private def create_activation_digest self.activation_token = User.new_token self.activation_digest = User.digest(activation_token) end # 生成随机token和加密的工具方法 def self.new_token SecureRandom.urlsafe_base64 end def self.digest(string) cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost BCrypt::Password.create(string, cost: cost) end
如果这些回调或方法缺失,用户的activation_digest会是nil,导致authenticated?返回false,激活逻辑不执行。
4. 确认数据库字段存在
确保users数据表有activated(布尔型,默认false)和activated_at(datetime型,默认nil)两个字段。如果字段缺失,update_attribute会静默失败(Rails不报错但数据不写入),导致user.reload.activated?仍为false。
5. 恢复user.activate方法(如果有定义)
如果你的User模型里定义了activate方法(一次性更新两个字段):
def activate update_columns(activated: true, activated_at: Time.zone.now) end
建议取消注释user.activate,删掉下面两个update_attribute调用,这种方式更高效且不易出错,可能直接解决问题。
内容的提问来源于stack exchange,提问作者user3250752

