Rails7中CurrentAttributes报错:Unsupported argument type (User)求助
问题描述
在Rails 7项目中使用ActiveSupport::CurrentAttributes存储当前用户,具体实现如下:
定义Current类
class Current < ActiveSupport::CurrentAttributes attribute :user end
ApplicationController设置当前用户
class ApplicationController < ActionController::Base before_action :set_current_user, if: :user_signed_in? private def set_current_user Current.user = current_user end end
Room模型中的相关方法
class Room < ApplicationRecord def send_partial_counter_and_users_list broadcast_update_to('users_in_room_list', target: 'users_room_' + self.id.to_s, partial: "rooms/users_in_room", locals: {users_in_room: users_in_room_list }) end def users_in_room_list user = User.find_by(Current.user) banned_by_me = Ban.where('user_id =?',user.id).pluck(:ban_id) users = User.where('id not in (?)',banned_by_me) @users = users @users end end
视图删除按钮
<% if @single_room %> <%= button_to '<i class="fa-solid fa-trash-arrow-up"> </i>'.html_safe, room_path(@single_room.id), :method => :delete%> <% end %>
执行房间删除(RoomsController#destroy)、消息创建时更新房间状态(如Room.where('id =? and is_private =?',params[:room_id], true).update(:mark_as_closed => false))等操作时,出现以下错误:
ArgumentError in RoomsController#destroy
Unsupported argument type: #User:0x00007fabf9af8168 (User)
Extracted source (around line #28):def users_in_room_list user = User.find_by(Current.user)
但Room模型的定时广播任务(每10秒执行send_partial_counter_and_users_list)运行时无此错误,需要解决该问题。
问题分析
错误核心原因是**User.find_by的使用方式错误**:
Current.user已经是完整的User实例对象,而find_by方法需要接收键值对形式的查询条件(如find_by(id: 1)),直接传入整个User对象会触发类型不支持的错误。- 定时任务无错误的概率原因:定时任务执行时
Current.user未被设置(值为nil),find_by(nil)返回nil,但后续代码若调用user.id本应报错,推测定时任务场景未触发该代码分支,或任务有额外上下文处理。
解决方案
1. 直接使用Current.user,无需重复查询
Current.user已经是当前登录用户的实例,不需要再通过find_by查询,同时增加空值判断避免报错:
def users_in_room_list user = Current.user # 未登录时返回空集合,避免后续调用user.id报错 return User.none unless user.present? banned_by_me = Ban.where(user_id: user.id).pluck(:ban_id) users = User.where.not(id: banned_by_me) @users = users end
2. 补充请求上下文清理(可选)
为避免Current属性在请求间泄露,建议在ApplicationController中添加请求结束后的清理操作:
class ApplicationController < ActionController::Base before_action :set_current_user, if: :user_signed_in? after_action :clear_current_attributes private def set_current_user Current.user = current_user end def clear_current_attributes Current.reset end end
3. 定时任务的上下文处理(如果需要)
如果定时任务需要正确获取用户上下文,需在任务执行时手动设置Current.user:
class RoomBroadcastJob < ApplicationJob def perform(room_id) room = Room.find(room_id) # 根据任务逻辑设置目标用户,比如指定系统用户或任务关联用户 Current.user = User.find(some_user_id) room.send_partial_counter_and_users_list Current.reset # 任务结束后清理上下文 end end
内容的提问来源于stack exchange,提问作者Wordica
相关产品推荐
相关产品推荐

