当用户尝试登录我们的Rails应用程序时,我会联系第三方ICAM服务器,该服务器返回有关用户的一些信息(如果他存在于ICAM服务器中)。我收到一个带有用户名,电子邮件等的哈希...(我们的环境配置方式是ICAM服务器可以根据工作站凭据检测到试图登录的人的身份)。
我们在自定义宝石中完成所有这些工作。在登录过程中,我尝试缓存ICAM服务器返回的信息,因此我不必再次与ICAM服务器通信。天真地,我有一些基本上做过的代码:
module Foo
def self.store_icam_data(data)
@icam_data = data
end
def self.icam_data
@icam_data || {}
end
end
我刚刚发现两个用户登录系统时出现问题。当用户A登录时,@icam_data
设置了他的信息。当用户B登录时,@icam_data
设置了他的信息。用户A下次发出请求时,@icam_data
内有用户B的信息,而不是用户A!
我不希望这个模块中的变量在线程/会话之间共享。它有效地使系统的所有当前用户成为登录的最后一个用户...一个非常粗糙的错误。
有人可以解释为什么这个@icam_data变量会在会话中共享吗?我期待数据/代码比显然更加孤立。
答案 0 :(得分:2)
只有两种方法可以在请求之间共享数据:数据库(RDBMS,Redis等)和session
对象(控制器内部)。任何其他改变并在请求结束时存活的数据都是副作用,应该避免。
您的类变量被保存到属于特定应用服务器进程的内存(RAM)区域(例如Unicorn工作进程)。单个进程自然会为很多请求提供服务,因为在每个请求上杀死和重启Rails都是低效的。
所以它不是" Rails共享代码"它的Web应用服务器在它所服务的所有请求中共享其内存区域。
如果要将少量数据绑定到当前用户,请使用session:
# save
session[:icam_data] = MyICAMModule.get_icam_data
# retain
MyICAMModule.set_icam_data(session[:icam_data])
session
中提供了有关{{1}}的更多信息。
如果您有大量数据 - 请使用数据库。