You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails国际象棋应用:Pieces控制器Show动作无法访问white_player_id

问题分析与修复方案

看起来你遇到的问题主要来自两个核心点:数据库字段未持久化和控制器代码的语法/逻辑错误,咱们一步步拆解解决:

1. Game模型回调未将white_player_id写入数据库

你的Game模型里的current_user_is_white_player是after_create回调,它只给white_player_id赋了值,但没有把这个变更保存到数据库里。模型测试能通过是因为测试中操作的是内存里的对象,而控制器读取的是数据库中的真实记录——数据库里的white_player_id其实是NULL,这就导致@piece.game.white_player_id返回nil,触发了render_not_found。

修复方案:

把回调改成before_create(在记录写入数据库前赋值,无需额外保存,更高效):

class Game < ApplicationRecord
  # 替换原来的after_create为before_create
  before_create :current_user_is_white_player

  def current_user_is_white_player
    self.white_player_id = user_id
  end

  # ... 其他代码保持不变
end

如果一定要用after_create,就在方法末尾加上save!强制保存变更,但before_create是更优的实现方式。

2. Pieces控制器show方法的语法与逻辑错误

你控制器里的代码存在注释导致的分支结构混乱:

if @piece.game.white_player_id # 控制器无法识别white_player_id,返回404错误
  # if @piece.piece_color_matches_user_color?(current_user)
    return render plain: "Success"
  else
    render_not_found
  end

注释掉内层if后,else会和外层的if @piece.game.white_player_id配对——只要white_player_id存在就返回Success,这完全偏离了你要校验"棋子颜色匹配用户"的核心逻辑,而且如果white_player_id是nil(数据库里没值),就会进入else返回404。

修复方案:

恢复正确的逻辑判断,直接调用你已经在模型里测试通过的piece_color_matches_user_color?方法:

def show
  @piece = Piece.find_by_id(params[:id])
  if @piece.blank?
    return render_not_found
  end

  if @piece.piece_color_matches_user_color?(current_user)
    render plain: "Success"
  else
    render_not_found
  end
end

3. 额外检查:FactoryBot游戏工厂

确保你的game工厂会关联一个有效的用户,这样white_player_id才能被正确赋值:

# spec/factories/games.rb
FactoryBot.define do
  factory :game do
    user { create(:user) } # 确保创建游戏时关联一个用户
    state { "pending" }
    # 其他必要字段按需添加
  end
end

验证修复

完成以上修改后:

  • 游戏创建时white_player_id会被正确写入数据库
  • 控制器会正确校验当前用户是否有权限查看该棋子
  • 你的控制器测试应该能顺利通过,返回200 Success状态码

内容的提问来源于stack exchange,提问作者Elizabeth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:49:37