2

对于这个冗长/复杂的问题,我深表歉意。

使用 rails 3.2.2 (ruby 1.9.3-p194),我们使用 Dalli/memcached 将用户特定的 ActiveRecord 模型对象保存到会话存储中,并且在开发过程中,我们有时会在从会话中检索数据时看到错误:

ArgumentError (Unable to unmarshal value: dump format error for symbol(0x46)):

通常,当数据有问题时会发生错误(例如,对象有一个指向不存在的记录的外键)。

但是,每当我们添加或删除涉及多对多关联的记录时,我们仍然会收到此错误,即使所有外键都是有效的并且一切似乎都是正确的(在删除数据库、杀死 rails 和 memcache 服务器等之后)。 )。

多对多关联是通过连接表和 has_many-through 实现的。我们模式的高度简化视图是:

  User
   |
 Profile
  |  \
  .   \
  .    \
  .     \
  |      \
 Foo ==== Bar

其中一个用户有很多个人资料,一个个人资料有很多 Foos(间接地,通过其他表),一个个人资料有很多条,并且 Foos 和 Bars 通过 BarFoo 连接表彼此有很多。

该错误通常在向/从 Bar 添加/删除 Foo 时触发。尽管我们在从 session 中检索时就意识到了这一点,但 session/memcache 本身并不是罪魁祸首,因为即使在数据存储在 session 中之前,错误也可能被迫发生。

为了从等式中消除会话,我在 Foo/Bar 记录创建/删除之后插入了以下代码:

Marshal.load(Marshal.dump(user)) # throws exception first time

这会引发异常。真正令人费解的是:如果我捕捉到异常以便可以继续处理请求,那么用户对象实际上是存储在会话中的,之后会毫无问题地被获取。(我发现这一点是因为在调试断点期间,运行上述代码一次失败,然后立即再次运行成功并在继续执行时“修复”问题。)

更奇怪的是,如果不是上面的代码,而是在 Foo/Bar 创建/删除之后立即执行以下操作:

Marshal.load(Marshal.dump(profile)) # does not throw any exception

我一点也不例外,其余代码都可以正常工作(用户从会话中存储和检索,没有错误)。

我读过很多讨论似乎说 AR 模型实例不应该被缓存,因为它们可能包含 procs、IO 等。但是,我们在转储对象时没有收到 TypeErrors。通过在用户模型上运行两次序列化/反序列化或在其子模型上运行一次来​​“纠正”问题的事实非常令人费解。一个对象的序列化表示怎么可能前一刻无效,下一刻有效?

谁能告诉我这是否是rails中的错误?还是我们正在做一些不受支持的事情?有没有办法将模型对象及其关联模型序列化,或者我是否必须为模型对象及其关联实现自己的序列化/反序列化代码?

更新:此错误不仅限于多对多关联。在架构中创建/更新/删除其他表时也会发生这种情况,但在这种情况下,这种情况要少得多,而且几乎不可能重现。

4

0 回答 0