在 Rails 的会话中存储对象

Posted

技术标签:

【中文标题】在 Rails 的会话中存储对象【英文标题】:Storing Objects in a Session in Rails 【发布时间】:2010-11-08 21:42:29 【问题描述】:

我一直被教导在会话中存储对象是一个坏主意。相反,应该存储 ID,以便在需要时检索记录。

但是,我想知道我有一个应用程序是该规则的一个例外。我正在构建一个抽认卡应用程序,被测验的单词在数据库中的一个表中,其架构不会改变。我想将当前正在测验的单词存储在会话中,以便用户可以在他们开始的地方完成,以防他们转到单独的页面。

在这种情况下,是否可以将这些单词作为对象存储在数据库中?如果是这样,为什么?我问的原因是因为测验旨在快速移动,我不想浪费数据库调用来检索一条从不改变的记录。但是,我不知道大型会话可能还有其他负面影响。

*作为记录,我已经尝试使用 Rails 2.3 中的内置 memcache 方法对其进行缓存,但显然每个项目的最大大小为 1MB。

【问题讨论】:

最大缓存大小为 1MB?这听起来不对。 一开始我很惊讶,但在我发现这一点之前遇到了非常奇怪的问题:code.google.com/p/memcached/wiki/…?虽然我只喜欢某种方式来缓存它,因为它可以解决我的问题。 哦,每个缓存项最多 1MB!我已经编辑了你的问题,以使那部分清楚。 啊,是的,很抱歉,感谢您的编辑 :) 【参考方案1】:

不在会话中存储对象的主要原因是,如果对象结构发生变化,你会得到一个异常。考虑以下几点:

class Foo
  attr_accessor :bar
end

class Bar
end

foo = Foo.new
foo.bar = Bar.new
put_in_session(foo)

然后,在项目的后续版本中,您更改了 Bar 的名称。您重新启动服务器,并尝试从会话中获取 foo。当它尝试反序列化时,找不到 Bar 并爆炸。

似乎很容易避免这个陷阱,但在实践中,我已经看到它咬了很多人。这只是因为序列化一个对象有时会比显而易见的更多(这种事情应该是透明的),除非你对此有严格的规则,否则事情往往会变得混乱。

它通常不受欢迎的原因是它在 ActiveRecord 中咬人是非常常见的,因为随着时间的推移,您的应用程序结构发生变化是很常见的,并且会话可以在最初一周或更长时间后反序列化已创建。

如果您了解所有这些并愿意投入精力以确保您的模型不会改变并且不会序列化任何额外的东西,那么您可能没问题。但要小心:)

【讨论】:

you change Bar's name,您能否更具体地了解此更改,例如,举个例子?在 Rails 4 应用程序中存储一个不太大的对象(一堆 id)时,我们观察到一些有趣的行为,但不确定发生了什么。谢谢。【参考方案2】:

Rails 倾向于鼓励 RESTful 设计,并且使用会话不是很 RESTful。我可能会制作一个包含一堆单词和 current_word 的测验资源。这样,当他们回来时,您就会知道他们在哪里。

现在,REST 并不是万能的(取决于您与谁交谈),但有一个很好的案例来应对大型会话。请记住,会话向磁盘写入内容和从磁盘写入内容,写入的数据越多,回读所需的时间就越长...

【讨论】:

【参考方案3】:

由于您的应用是 Rails 应用,我建议:

    利用客户端的缓存能力 通过在 javascript 中缓存卡片。 (你需要一个相当 ajaxy 的应用程序来 这样做,请参阅最新的 RailsCast 了解有关 javascript 页面缓存的一些有趣点) 使用许多其他 Rails 支持的服务器端之一 缓存选项(即 MemCached)到 缓存这些数据。

【讨论】:

【参考方案4】:

当您使用 CookieStore(我相信 Rails 2+ 中的默认设置)时,您会遇到直接在会话中存储对象的一个​​更隐蔽的问题。很容易出现 CookieOverflow 错误,很难从中恢复。

【讨论】:

以上是关于在 Rails 的会话中存储对象的主要内容,如果未能解决你的问题,请参考以下文章

Rails:如何在会话中存储数据?

会话存储在 Rails 中的啥位置?

在 Rails 中存储持久会话数据而不影响正常会话过期

在会话存储中保存用户对象

护照js如何在会话中存储用户对象?

如何在单独的表单页面上存储和访问存储在会话对象中的值