views:

51

answers:

1

I'm looking to serialize an incomplete/temporary model as an attribute of another model such as:

class User < ActiveRecord::Base
  serialize :pending_post
end

Where pending_post is assigned an activerecord model:

...
user.pending_post = Post.new(:title => "Whatever", :message => "whatever")
user.save

But instead of saving the yaml for the new Post model, the pending_post attribute is nil (in the DB and on reload). The serialize works great with other objects, Hashes, Arrays, etc, but comes up nil in this case. This is Rails 2.3.9, but I did a quick test with 3.0.1 and saw the same results. I found this description of the issue from years ago: http://www.ruby-forum.com/topic/101858.

I know I could manually serialize/deserialize the object (which works fine) or serialize just the post.attributes, but I'm curious if anyone knows why this acts as it does? It seems if the new post is saved before being assigned to user.pending_post, then just the ID is saved as the user.pending_post attribute. I'm pretty sure it's intentional and not a bug, but I quite don't understand the reasoning. Is it poor form to serialize an active_record model?

+1  A: 

I think you need to serialize/save the attributes, not the post object itself, like so:

user.pending_post = {:title => 'Whatever', :message => 'whatever'}
user.save

Then later you can turn it into a real post:

user.posts.create user.pending_post

And I'd probably take it a step further (as I so often do) with a user method:

def save_post
  self.posts.create self.pending_post
end

I hope this helps!

Jaime Bellmyer
Yeah, this is one of the options I'm exploring. Do you have idea why this is necessary? Manually serializing/deserializing a Post with yaml seems to work fine. Why would "serialize :attr_name" treat it differently than other objects?
njorden
That's a good question, and I don't know the answer. I know it's a simpler process to store just an attribute hash, and ruby objects can be more complex than they first seem. Instance variables, for example, can be dynamically created during the object's lifetime, and I don't know if issues like that can complicate things. Contrast a ruby object with a c/c++ object, where some quick math can tell you exactly how many bytes each object takes in memory. Dynamic means complicated :)
Jaime Bellmyer
Actually, the more I think about it, the harder and less efficient it would be to try to stuff a ruby object into a text blob. If Rails wanted to support it, they'd have to account for the fact that instance variables AND methods can be created on the fly. The only way to safely store a ruby object is to store *all* the code that makes up that object. All the instance variables and method definitions that make up that method at the time it's stored. Not to mention inheritance issues.
Jaime Bellmyer
It just seems a bit inconsistent (or not well documented?) because "serialize :attr_name" works as advertised for any other arbitrary ruby object that you create, just not objects that subclass ActiveRecord::Base. I realize that you have to be careful with this because of the dynamic nature of ruby objects, but is there some additional gotcha associated with serializing activerecord objects that doesn't apply to other ruby objects?
njorden
The documentation for serialize says for "arrays, hashes, and other non-mappable objects". I don't know what that means, but maybe they mean mappable to the database (ie, ActiveRecord). Maybe that's to prevent recursion. ActiveRecord objects that contain ActiveRecord objects would really start to degrade your database performance. And it'd be interesting to see what happens if you're allowed to assign two objects to each other :)
Jaime Bellmyer
By the way, I feel like I've put a lot into this, and I'd appreciate your accepting the answer. It may not be what you were looking for, but it's the best solution Rails has to offer.
Jaime Bellmyer
Ah, of course I missed that in the documentation because it's a heading and was right in front of my face (d'oh!). It would be nice if the documentation was a bit more explicit or there was an explanation of the reasoning, because you can do it manually but it seems it's not a great idea. I guess the way to go for models to serialize the attributes of the model as you've suggested. Thanks for the help!
njorden