当存在更多用户时,用户更新测试失败
User update test fails when more users present
完成第 10 章中的教程,一切正常,测试绿色,没有任何问题。但是,当我按照 清单 10.47 添加更多用户时,'update user with friendly forwarding' 测试开始失败。
FAIL["test_successful_edit_with_friendly_forwarding", UsersEditTest, 1.8292690003290772]
test_successful_edit_with_friendly_forwarding#UsersEditTest (1.83s)
Expected response to be a redirect to <http://www.example.com/users/762146111> but was a redirect to <http://www.example.com/users/14035331>.
Expected "http://www.example.com/users/762146111" to be === "http://www.example.com/users/14035331".
test/integration/users_edit_test.rb:35:in `block in <class:UsersEditTest>'
我对此进行了一些测试,当我从 users.yml 中删除用户时,测试再次通过。所以我的代码中有一个错误,只有当应用程序中有超过 2 个用户时才会出现。这是我的测试:
users_edit_test.rb
require 'test_helper'
class UsersEditTest < ActionDispatch::IntegrationTest
def setup
@user = users(:michael)
end
test 'unsuccessful edit' do
log_in_as(@user)
get edit_user_path(@user)
assert_template 'users/edit'
patch user_path(@user), params: { user: { name: '',
email: 'foo@invalid',
password: 'foo',
password_confirmation: 'bar' } }
assert_template 'users/edit'
assert_select 'div.alert',
'The form contains 4 errors.'
end
# This is the failing test
test "successful edit with friendly forwarding" do
get edit_user_path(@user)
log_in_as(@user)
assert_redirected_to edit_user_url(@user)
name = "Foo Bar"
email = "foo@bar.com"
patch user_path(@user), params: { user: { name: name,
email: email,
password: "",
password_confirmation: "" } }
assert_not flash.empty?
assert_redirected_to @user #The test is failing on this line
@user.reload
assert_equal name, @user.name
assert_equal email, @user.email
end
end
查看错误,似乎 user_path(@user)
返回了错误的用户。我测试了一下,好像补丁请求失败了,用户名和邮箱是原来的用户名和密码,不是补丁请求里设置的。这可能是因为它正在修补错误的用户,但我不明白为什么或如何。当我测试找出@user 的值时,据我所知,它总是解析为 users.yml 中的第一个用户。
users.yml
michael:
name: Michael Example
email: michael@example.com
password_digest: <%= User.digest('password') %>
admin: true
archer:
name: Sterling Archer
email: duchess@example.gov
password_digest: <%= User.digest('password') %>
lana:
name: Lana Kane
email: hands@example.gov
password_digest: <%= User.digest('password') %>
malory:
name: Malory Archer
email: boss@example.gov
password_digest: <%= User.digest('password') %>
<% 30.times do |n| %>
user_<%= n %>:
name: <%= "User #{n}" %>
email: <%= "user-#{n}@example.com" %>
password_digest: <%= User.digest('password') %>
<% end %>
如果我删除其他用户并仅保留前两个用户,则测试现在通过了。这是我编写测试时所处的状态。现在,我的分页测试反而失败了,因为没有足够的用户进行分页。本来就是这样。
我对 Rails 相当陌生(教程和所有内容),尤其是测试方面的新手。我已经尝试了各种技术来临时更改测试以弄清楚出了什么问题,但老实说我无法追踪错误在哪里。我已经将我所有的代码与提供的代码进行了比较,没有看到任何拼写错误或错误,但肯定有问题。
奇怪的是,我根本无法在 Heroku 上的开发或生产中复制该错误。据我所知,作为用户和查看日志,该应用程序的行为都应该如此。但测试仍然失败——我一定是在某处引入了错误。或者我的测试是错误的,但我看不出与教程中的代码有什么不同。
我见过类似的问题,例如 this one,但据我测试,重定向的问题是有效的。此外,如果我更改我的测试以取消重定向,并测试 only 用户更新,测试仍然失败。所以问题很可能出在我的用户更新方法上。
user_controller.rb
class UsersController < ApplicationController
before_action :logged_in_user, only: [:index, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
def index
@users = User.paginate(page: params[:page])
end
def show
@user = User.find(params[:id])
end
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
log_in @user
flash[:success] = 'Welcome to the Sample App!'
redirect_to @user
else
render 'new'
end
end
def edit
@user = User.find_by(params[:user_id])
end
def update
@user = User.find_by(params[:user_id])
if @user.update_attributes(user_params)
flash[:success] = 'Profile Updated'
redirect_to @user
else
render 'edit'
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted"
redirect_to users_url
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
# Before filters
# Confirms a logged-in user.
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
# Confirms the correct user.
def correct_user
@user = User.find(params[:id])
redirect_to(root_url) unless current_user?(@user)
end
# Confirms an admin user.
def admin_user
redirect_to(root_url) unless current_user.admin?
end
end
我的问题确实是我的用户更新方法。我使用 find_by
方法 select 用户,而不是 find
.
这是固定的用户更新方法:
def update
@user = User.find(params[:id]) # "find" method instead of "find_by"
if @user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to @user
else
render 'edit'
end
end
现在所有测试都正确通过了。
您可以通过以下方式获取记录:
@user = User.find_by_id(params[:user_id])
或
@user = User.find(params[:user_id])
或
@user = User.where(id: params[:user_id]).first
完成第 10 章中的教程,一切正常,测试绿色,没有任何问题。但是,当我按照 清单 10.47 添加更多用户时,'update user with friendly forwarding' 测试开始失败。
FAIL["test_successful_edit_with_friendly_forwarding", UsersEditTest, 1.8292690003290772]
test_successful_edit_with_friendly_forwarding#UsersEditTest (1.83s)
Expected response to be a redirect to <http://www.example.com/users/762146111> but was a redirect to <http://www.example.com/users/14035331>.
Expected "http://www.example.com/users/762146111" to be === "http://www.example.com/users/14035331".
test/integration/users_edit_test.rb:35:in `block in <class:UsersEditTest>'
我对此进行了一些测试,当我从 users.yml 中删除用户时,测试再次通过。所以我的代码中有一个错误,只有当应用程序中有超过 2 个用户时才会出现。这是我的测试:
users_edit_test.rb
require 'test_helper'
class UsersEditTest < ActionDispatch::IntegrationTest
def setup
@user = users(:michael)
end
test 'unsuccessful edit' do
log_in_as(@user)
get edit_user_path(@user)
assert_template 'users/edit'
patch user_path(@user), params: { user: { name: '',
email: 'foo@invalid',
password: 'foo',
password_confirmation: 'bar' } }
assert_template 'users/edit'
assert_select 'div.alert',
'The form contains 4 errors.'
end
# This is the failing test
test "successful edit with friendly forwarding" do
get edit_user_path(@user)
log_in_as(@user)
assert_redirected_to edit_user_url(@user)
name = "Foo Bar"
email = "foo@bar.com"
patch user_path(@user), params: { user: { name: name,
email: email,
password: "",
password_confirmation: "" } }
assert_not flash.empty?
assert_redirected_to @user #The test is failing on this line
@user.reload
assert_equal name, @user.name
assert_equal email, @user.email
end
end
查看错误,似乎 user_path(@user)
返回了错误的用户。我测试了一下,好像补丁请求失败了,用户名和邮箱是原来的用户名和密码,不是补丁请求里设置的。这可能是因为它正在修补错误的用户,但我不明白为什么或如何。当我测试找出@user 的值时,据我所知,它总是解析为 users.yml 中的第一个用户。
users.yml
michael:
name: Michael Example
email: michael@example.com
password_digest: <%= User.digest('password') %>
admin: true
archer:
name: Sterling Archer
email: duchess@example.gov
password_digest: <%= User.digest('password') %>
lana:
name: Lana Kane
email: hands@example.gov
password_digest: <%= User.digest('password') %>
malory:
name: Malory Archer
email: boss@example.gov
password_digest: <%= User.digest('password') %>
<% 30.times do |n| %>
user_<%= n %>:
name: <%= "User #{n}" %>
email: <%= "user-#{n}@example.com" %>
password_digest: <%= User.digest('password') %>
<% end %>
如果我删除其他用户并仅保留前两个用户,则测试现在通过了。这是我编写测试时所处的状态。现在,我的分页测试反而失败了,因为没有足够的用户进行分页。本来就是这样。
我对 Rails 相当陌生(教程和所有内容),尤其是测试方面的新手。我已经尝试了各种技术来临时更改测试以弄清楚出了什么问题,但老实说我无法追踪错误在哪里。我已经将我所有的代码与提供的代码进行了比较,没有看到任何拼写错误或错误,但肯定有问题。
奇怪的是,我根本无法在 Heroku 上的开发或生产中复制该错误。据我所知,作为用户和查看日志,该应用程序的行为都应该如此。但测试仍然失败——我一定是在某处引入了错误。或者我的测试是错误的,但我看不出与教程中的代码有什么不同。
我见过类似的问题,例如 this one,但据我测试,重定向的问题是有效的。此外,如果我更改我的测试以取消重定向,并测试 only 用户更新,测试仍然失败。所以问题很可能出在我的用户更新方法上。
user_controller.rb
class UsersController < ApplicationController
before_action :logged_in_user, only: [:index, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
def index
@users = User.paginate(page: params[:page])
end
def show
@user = User.find(params[:id])
end
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
log_in @user
flash[:success] = 'Welcome to the Sample App!'
redirect_to @user
else
render 'new'
end
end
def edit
@user = User.find_by(params[:user_id])
end
def update
@user = User.find_by(params[:user_id])
if @user.update_attributes(user_params)
flash[:success] = 'Profile Updated'
redirect_to @user
else
render 'edit'
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted"
redirect_to users_url
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
# Before filters
# Confirms a logged-in user.
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
# Confirms the correct user.
def correct_user
@user = User.find(params[:id])
redirect_to(root_url) unless current_user?(@user)
end
# Confirms an admin user.
def admin_user
redirect_to(root_url) unless current_user.admin?
end
end
我的问题确实是我的用户更新方法。我使用 find_by
方法 select 用户,而不是 find
.
这是固定的用户更新方法:
def update
@user = User.find(params[:id]) # "find" method instead of "find_by"
if @user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to @user
else
render 'edit'
end
end
现在所有测试都正确通过了。
您可以通过以下方式获取记录:
@user = User.find_by_id(params[:user_id])
或
@user = User.find(params[:user_id])
或
@user = User.where(id: params[:user_id]).first