ActiveRecord Model Object in Session

Am I setting myself up for disaster by storing an ActiveRecord model in the session before saving it to the database? I’ve heard that they aren’t serializable and that this is a bad idea… If so, is there any way to serialize the record for session storage? This technique just seems so useful for me… (ie multiple step checkout, etc.)

Thanks,

Chad

you're better off storing the object id in the session object.

session[:object] = myobject.id

then you can reload the object by

myobject = MyObject.find(session[:object])

then each action can update the object in turn

IMHO this is a good way to prevent session issues. My understanding is that you’ll need to do some clever validataions for multi step forms and such. Otherwise you could have a situation where you have not got valid models and thus they won’t save.

Something like

class MyModel < ActiveRecord::Base

attr_accessor :step

validates_xxxx ,:if => Proc.new{ |model| model.step >= 3 }

end

might do the job…

I’d be interested to see how other ppl sort this out though…

Cheers

Thanks Brian for the suggestion... I might end up doing that but I'd prefer not to write to the database prematurely (ie before the final review and submit button in checkout has been pressed). Sure I can store the status and just set the status to incomplete until the process is complete, but this is simply not ideal in many cases. That would seem to leave a lot of unnecessary database integrity issues.

Any other way to serialize the object?

Brian Gibson wrote:

Brian Gibson wrote:

you're better off storing the object id in the session object.

session[:object] = myobject.id

then you can reload the object by

myobject = MyObject.find(session[:object])

then each action can update the object in turn

On an existing object yes. But the original poster said they wanted to store a new unsaved object in the session. It does not seem like there would be any problem with this since there is no issue of contention. But I'm not extremely knowledgeable about ActiveRecord so perhaps there is some valid reason for saying no in this case.

In any case it seems like you could just store a hash of attributes in the session as you go through the multi-page form and then at the end do:

MyObject.create session[:my_obj]

Where session[:my_obj] is just a hash of attributes that are assigned as the form progresses. But I still think using an unsaved ActiveRecord object would be just as safe as a Hash.

Eric

What about using a Struct or OpenStruct that mimics your model, and sticking that into the session? You could also assign values to your model, validate them, and then if the validation succeeds don't save the model but do save the struct. Then when you are finally ready to save the model you could do something like so:

inst = Record.new(mystruct)

At least I think that would work

I like the idea of storing a hash of attributes. The serialization is in your control.

Now there's nothing wrong with creating a new object and saving it before all the data is ready. For example, you have objects that have a parent-child relationship. You create the parent first. Then you create the children in a loop (parent.children.create). While creating the children, you process them to get some intrinsic value like count (a simplistic example already provided by acts_as_tree). Then post-loop you update the parent with the calculated value.

Of course, you could simply use the new method instead of create and save the parent at the end, which will save the parent and children at the same time. However if your object tree is being created recursively, and the tree is made up of a lot of objects, and the tables that store the objects are wide, well you can run out of memory quickly.

In any case, a solution is highly dependent on the circumstances and problem to be solved. There's no one size fits all.

But when it comes to storing data in a session variable, the less complex the better. As Frederick says, if you change your model and forget to update how you store model data in the session, something will go wrong.

Also you really should avoid storing critical data in a session. If a cookie is lost or deleted, the application can lose track of the session. Storing it in a database object like a Struct can be handy in that case.

Then of course there's the old stand-by of playing hot potato, and passing the data from one form and populating hidden fields of the next form.

Or you can be really hip and AJAXy and use script.aculo.us to hide and unhide portions of a megalithic form which will make your server-side code much simpler (1 method rather than a series of methods, 1 form instead of many) yet to the user it'll be a wizard-like interface that is VERY responsive. Plus it'll be easier to debug and update since it is only one form, and you can always switch off the form_remote_tag to regular form_tag while developing (which is recommended... get your non-AJAX stuff working first).

So many options. :slight_smile:

oh I should clarify...form_remote_tag (XmlHttpResponse) and script.aculo.us are separate features. You don't need one to make use of the other. It's just they are used together very often. Your form can have all these nifty hide/unhide events but depending on the scope of the data being entered, it should post like a regular form if that's the desired behavior.

Awesome thanks guys... that is definitely sufficient information to go off of. I'll probably validate the model object but store a hash or [open]struct in the session.

Chad