長くて複雑な質問で申し訳ありません。
Rails 3.2.2 (ruby 1.9.3-p194) を使用して、ユーザー固有の ActiveRecord モデル オブジェクトをセッション ストアに Dalli/memcached を使用してセッションに保存しています。開発中に、セッションからデータを取得するときにエラーが発生することがあります。
ArgumentError (Unable to unmarshal value: dump format error for symbol(0x46)):
通常、エラーはデータに問題がある場合に発生します (たとえば、オブジェクトに存在しないレコードを指す外部キーがある場合など)。
ただし、すべての外部キーが有効で、すべてが正しいように見えても (データベースを吹き飛ばしたり、Rail や memcache サーバーを強制終了した後など)、多対多の関連付けを含むレコードを追加または削除するたびに、このエラーが発生します。 )。
多対多の関連付けは、結合テーブルと has_many-through を使用して実装されます。スキーマを非常に単純化すると、次のようになります。
User
|
Profile
| \
. \
. \
. \
| \
Foo ==== Bar
User には多くのプロファイルがあり、Profile には多くの Foo があり (間接的に他のテーブルを介して)、Profile には多くの Bar があり、Foo と Bar は BarFoo 結合テーブルを介して互いに多くのプロファイルを持っています。
このエラーは通常、Foo を Bar に追加/Bar から削除するときに発生します。セッションから取得する時点で認識しましたが、データがセッションに保存される前でもエラーが強制的に発生する可能性があるため、セッション/memcache 自体に問題はありません。
方程式からセッションを除外するために、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 などが含まれている可能性があるため、キャッシュすべきではないと思われる多くの議論を読んだことがあります。User モデルでシリアライゼーション/デシリアライゼーションを 2 回実行するか、その子モデルで 1 回実行することによって問題が「修正」されるという事実は、非常に不可解です。オブジェクトのシリアル化された表現がある瞬間に無効になり、次の瞬間に有効になるのはどうしてでしょうか?
これがレールのバグかどうか誰か教えてもらえますか? または、サポートされていないことを行っていますか? モデル オブジェクトを関連付けられたモデルでシリアル化する方法はありますか? または、モデル オブジェクトとその関連付けに対して独自のシリアル化/逆シリアル化コードを実装する必要がありますか?
更新: このエラーは、多対多の関連付けに限定されません。スキーマ内の他のテーブルを作成/更新/削除するときにも発生しますが、そのような場合ははるかにまれであり、再現することは事実上不可能です.