用户有个人资料,应该可以更新。
我更新配置文件,例如将名称更改为“Homer Simpson”,但所有断言都失败,因为数据库记录似乎没有更新。
我似乎无法获得更新的属性:
Failure/Error: expect(subject.current_user.first_name).to eq('Homer')
expected: "Homer"
got: "Lew"
(compared using ==)
# ./spec/controllers/registrations_controller_spec.rb:67:in `block (3 levels) in <top (required)>'
N.B。我试过了@user.reload
和subject.current_user.reload
规格仍未通过。
我正在使用:
我已经查过:
devise.mapping
设置为用户valid_session
将设计会话污染为per this other Stackoverflow thread。registrations_controller_spec.rb
describe "User Profiles" do
login_user
it "Update - changes the user's attributes" do
put :update, id: @user, user: attributes_for(:user, first_name: 'Homer')
@user.reload
expect(@user.first_name).to eq('Homer') # FAILS
end
end
我尝试在此Stackoverflow主题中更换@user
subject.current_user
:"Devise Rspec registration controller test failing on update as if it was trying to confirm email address"
put :update, id: subject.current_user, user: attributes_for(:user, first_name: 'Homer')
subject.current_user.reload
expect(subject.current_user.first_name).to eq('Homer') # Still FAILS
但它仍然失败。
控制器中有问题吗?我按current_user.id
而不是params[:id]
找到了用户。
registrations_controller.rb
def update
@user = User.find(current_user.id)
email_changed = @user.email != params[:user][:email]
password_changed = !params[:user][:password].blank?
if email_changed or password_changed
successfully_updated = @user.update_with_password(user_params)
else
successfully_updated = @user.update_without_password(user_params)
end
if successfully_updated
sign_in @user, bypass: true # Sign in the user bypassing validation in case his password changed
redirect_to user_profile_path, notice: 'Profile was successfully updated.'
else
render "edit"
end
end
controller_macros.rb - 定义login_user
帮助
module ControllerMacros
def login_user
before(:each) do
@request.env["devise.mapping"] = Devise.mappings[:user]
@user = FactoryGirl.create(:user)
@user.confirm!
sign_in @user
end
end
end
我的集成规格很好。我在控制器中缺少什么?
答案 0 :(得分:2)
我的回答可以解决您的问题,但不能直接修复代码中的错误。要做到这一点,我需要编写更多测试和动手调试,我只是通过阅读来解决这个问题并不是很有经验:)
我建议你不要覆盖Devise的RegistrationsController。与原始代码相比,您的代码至少缺少两件事:
没有current_user对象的副本。在真实应用中,current_user将通过提交不合适的表单进行注销。
缺乏参数消毒
剩下的错误。
我的建议是直接使用Devise的方法,因为您的代码中没有没有特殊,也无需覆盖完整代码。
class RegistrationsController < Devise::RegistrationsController
def update
end
# Or even without this method.
end
就是这样。
不需要密码
def update
params.merge!(password: current_user.password) if params[:password].blank?
super
end
对于测试,只需编写一些临时集成测试。 Devise有完整的涵盖功能测试,因此无需重复。
答案 1 :(得分:0)
尝试assigns
it "Update - changes the user's attributes" do
put :update, id: @user, user: attributes_for(:user, first_name: 'Homer')
homer = assigns(:user)
@user.reload
expect(homer.first_name).to eq('Homer')
end
更新:根据Billy Chan的评论,这应该正确测试该名称是否正在更新
it "Update - changes the user's attributes" do
put :update, id: @user, user: attributes_for(:user, first_name: 'Homer')
homer = assigns(:user)
@user.reload
#expect(homer.first_name).to eq('Homer') Peter and Billy are right, this only tests
# that the attribute was actually assigned, not that the update was successful
expect(@user.first_name).to eq(homer.first_name)
#however this test that the users updated `first_name` matches the attribute
#in the test
end
注意:
我的答案基于几个月前我经历过的Michael Hartl教程 - 他使用这种方法,我相信他解释了原因 - 虽然我没有屏幕投射在我面前时刻。我稍后再仔细查看。
视频:
Here's the video - 它的质量非常低,因为我只是使用了quicktime的屏幕记录 - 并且在开始时有一些残酷的反馈循环,因此在最初几秒钟静音您的计算机。
答案 2 :(得分:0)
感谢大家的建议,这些建议帮助我了解了我的代码并找到了问题。
失败原因:默认出厂时包含电子邮件和密码,因此控制器测试一直试图更改用户密码。
具体而言,我在 registrations_controller_spec.rb
中更改了这行代码put :update, id: @user, user: attributes_for(:user, first_name: 'Homer')
为:
patch :update, id: @user, user: attributes_for(:user_params, first_name: 'Homer', last_name: 'Simpson')
然后我不得不更新我的工厂,因此我可以使用 :user_params
代替更新:
FactoryGirl.define do
factory :user do
first_name { Faker::Name.first_name }
last_name { Faker::Name.last_name }
sequence(:username) { |n| "user-#{n}" }
email { Faker::Internet.email }
password { Faker::Lorem.characters(8) }
end
factory :user_params, class: :user do
first_name { Faker::Name.first_name }
last_name { Faker::Name.last_name }
factory :user_params_with_email, class: :user do
email { Faker::Internet.email }
end
factory :user_params_with_password, class: :user do
password { Faker::Lorem.characters(8) }
end
end
end
感谢所有提出建议的人。它帮助我解开了我的代码,@ billy-chan指出问题是对的,我修复了。
比较进出控制器的参数。
我的集成测试正在通过,因为我没有尝试更改电子邮件或密码。