我正在编写一个包含多个“房间”供用户加入的应用程序。每个房间的用户会话应该相互独立。
例如,用户应该能够访问
/room/1
并以 user1
登录,访问 /room/2
并以 user2
登录,而无需在 user1
中从 /room/1
注销。签入/注销一个房间不应影响其他房间的会话。
这可以在 Devise 中完成吗?如果不是,实现此行为的可能选项是什么?
我读过有关 Devise 范围的信息,但似乎 Devise 的范围需要预定义并分成不同的模型,这在这种情况下是不可能的(房间可以在运行时创建)。
编辑:
为了解决问题,我不需要跟踪用户的在线或离线状态——传统的基于 cookie 的会话就足够了,它只需要在每个房间范围内。
我可以想象如果我需要从头开始实现这个,我会将每个房间的会话 cookie 存储在不同的 cookie 中。我只是问是否有现有的宝石能够实现这一目标。
我认为您应该为这个功能想象一个单独的系统,它与 Devise 或您选择使用的任何身份验证系统共存。并非所有内容都应塞入您的身份验证系统。
身份验证系统将负责用户登录应用程序并跟踪凭据,而用户表和聊天室之间的简单连接表会跟踪在(或曾经在)房间中的用户。
# This is the actual user that signs into your application
class User < ApplicationRecord
# ...
has_many :room_users
has_many :rooms, through: :room_users
end
# this is just a member of a chat room
# rails g model room_user nickname:string user:belongs_to room:belongs_to left_at:date_time
class RoomUser < ApplicationRecord
belongs_to :room
belongs_to :user
def soft_delete
update_attribute(:left_at, Time.current)
end
end
class Room < ApplicationRecord
has_many :room_users
end
class RoomUsersController
before_action :authenticate_user!
before_action :set_room!
# Joining a room
# POST /rooms/1/room_users
def create
@room_user = @room.room_users.new(room_user_params) do |ru|
ru.user = current_user
end
if @room_user.save
render json: @room_user,
status: :created
else
render json: { errors: @room_user.errors.full_messages },
status: :unprocessable_entity
end
end
# Leaving a room
# DELETE /room_users/1
def destroy
@room_user = @room.room_users.find_by!(user_id: current_user.id)
@room_user.soft_delete
head :no_content
end
private
def set_room
@room = Room.find(params[:room_id])
end
def room_user_params
params.require(:room_user)
.permit(:nickname)
end
end
这可以在 Devise 中完成吗?
是和不是。 Rails(以及扩展的 Devise)默认使用基于 cookie 的会话存储。这意味着无法跟踪用户在任何给定时间签署的内容,因为该信息由客户持有。
如果你想实现它,你需要将会话存储切换到数据库存储或类似 memcached/redis 的东西。
更好的问题是:这应该在 Devise 中完成吗?我认为答案是否定的,因为它已经做了很多疯狂的事情而且非常复杂。