Marshal not serializing or deserializing nested serialized attributes properly-Collection of common programming errors

This is kind of a tough problem to explain, because I don’t really know what is going on. I’ve made a repository with instructions of how to reproduce:

https://github.com/bricker/cache_nested_serialized_attributes

Basically:

  • User has_many Posts
  • Post has serialized attribute :metadata

And to reproduce:

users = User.first(2)
users.first.posts.first
users.last.posts.first
dump = Marshal.dump(users)
Marshal.load(dump)
=> [#, 
    :@new_record]

You can see the unexpected output in that final line. It only seems to occur under those specific conditions. Just calling users.first.posts works fine. Not calling .posts at all works fine. It’s only when I load a specific post from a user before dumping that this happens.

The main difference I notice between Rails 4 (which works properly) and Rails 3.2.13 (which doesn’t work) is that when calling Marshal.dump(users) in Rails 3, the Posts are reloaded:

dump = Marshal.dump(users)
  Post Load (0.2ms)  SELECT "posts".* FROM "posts" WHERE "posts"."user_id" = 1
  Post Load (0.2ms)  SELECT "posts".* FROM "posts" WHERE "posts"."user_id" = 2

… which doesn’t happen in Rails 4.

I wish I could explain better but it’s such an obscure problem. Please ask questions if you need clarification, and look at or clone the repo.

This is tested and confirmed on a vanilla Rails 3.2.13 (see repository). This behavior does not happen in Rails 4.

Thanks!