Rails中Rspec单元测试:current_user更新后@group_user未同步问题
问题分析与解决方案
这是典型的Active Record实例缓存导致的问题——Rails会把从数据库加载的对象保存在内存中,当数据库里的记录被修改后,内存中的对象不会自动同步最新数据,除非你主动触发刷新。
具体原因
你的测试里,@group_user是在测试开始时就加载到内存的实例。当你调用get :get_users后,get_users方法里更新了current_user.user_detail(也就是@group_user的关联记录),这个更新是直接写入数据库的,但测试代码里的@group_user.user_detail还是停留在初始加载的旧状态,所以断言会失败。而你在binding.pry里看到current_user的user_detail是最新的,是因为current_user是在请求过程中从session重新加载的实例,它的状态是数据库的最新值。
修复方案
你只需要在请求之后,主动刷新内存中的user_detail实例即可,有几种简单的方式:
方式1:刷新关联的user_detail实例
在get请求之后,调用reload方法重新从数据库加载最新数据:
describe "#test_feature" do it "should test this feature" do sign_in @group_user get :get_users, {name: "darpan"} # 重新加载user_detail的最新状态 @group_user.user_detail.reload expect(@group_user.user_detail.name).to eq("darpan") sign_out @group_user end end
方式2:刷新整个@group_user实例
如果需要确保整个用户对象及其关联都是最新的,可以直接刷新@group_user:
describe "#test_feature" do it "should test this feature" do sign_in @group_user get :get_users, {name: "darpan"} # 重新加载用户及关联的所有数据 @group_user.reload expect(@group_user.user_detail.name).to eq("darpan") sign_out @group_user end end
方式3:直接查询数据库(不推荐,但可用)
你也可以绕过内存中的实例,直接从数据库查询最新记录:
expect(UserDetail.find(@group_user.user_detail.id).name).to eq("darpan")
不过这种方式不如reload简洁,也没必要多一次数据库查询。
额外提示
在Rails测试中,只要涉及到数据库修改后断言内存中的对象,都要记得考虑实例缓存的问题——主动调用reload是最常用的解决办法。
内容的提问来源于stack exchange,提问作者Darpan
相关产品推荐
相关产品推荐

