Game模型调用update_attribute返回true,但部分属性未实际更新
排查Game模型turn属性未更新的问题
我来帮你分析下这个问题~你提到opponent能成功更新,但turn没变化,而且update_attribute还返回true,这种情况通常是这几个原因导致的,咱们一步步排查:
1. 先确认owner的值是否正确
你代码里owner = @game.owner.id.to_i,首先要确保@game.owner不是nil——如果游戏还没设置owner,那@game.owner.id会报错,但你说方法返回true,所以大概率owner是存在的,但可以加个日志验证下:
def update @game = Game.find(params[:id]) owner = @game.owner.id.to_i Rails.logger.debug "当前游戏owner的ID是:#{owner}" # 去日志里看这个值是不是你预期的 @game.update_attribute(:opponent, current_user) turn_update_result = @game.update_attribute(:turn, owner) Rails.logger.debug "更新turn的结果:#{turn_update_result},更新后turn的值:#{@game.turn}" end
如果日志里显示owner是0或者非预期的数值,那问题就出在这里,得先确保@game.owner是正确的用户对象。
2. 检查模型是否有回调覆盖了turn的值
如果owner值没问题,那很可能是Game模型里的回调(比如after_save、before_save)在你更新后又修改了turn。比如模型里如果有类似这样的代码:
after_save :reset_turn def reset_turn self.turn = 1 # 每次保存后把turn重置为1,就会覆盖你的更新 end
这种情况下,你更新turn后,回调会再次修改它。可以暂时注释掉这类回调,测试下是否能正常更新。
3. 合并更新操作,避免多次保存的问题
你现在用两次update_attribute,每次都会触发一次数据库保存,不如合并成一次更新,既高效又能避免中间回调的干扰:
- 如果需要触发验证和回调,用
update:
def update @game = Game.find(params[:id]) owner_id = @game.owner.id # 一次更新两个属性 @game.update(opponent: current_user, turn: owner_id) end
- 如果不需要触发验证和回调(比如确定数据没问题,不想触发多余的回调),用
update_columns(注意关联属性要写字段名,比如opponent_id而不是opponent):
def update @game = Game.find(params[:id]) owner_id = @game.owner.id @game.update_columns(opponent_id: current_user.id, turn: owner_id) end
4. 检查数据库字段约束
最后可以去数据库里看看turn字段的设置:比如是不是设置了默认值,或者有NOT NULL约束导致更新失败?不过update_attribute返回true说明ActiveRecord认为保存成功了,所以这个概率较低,但也可以确认下。
另外,如果你在更新后立刻查看@game.turn,有时候需要调用@game.reload才能拿到数据库里的最新值,因为内存里的对象可能还没同步~
内容的提问来源于stack exchange,提问作者swilliams
相关产品推荐
相关产品推荐

