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

On 9/22/06, Brian G. [email protected] wrote:

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 G. 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.

You definitely want to be careful about storing complex objects in your
session, sooner or later it will bite you. For example if you change the
class of the stored object sufficiently Rails eon’t be able to
unserialize the object stored in the session and your users will get a
cryptic error message.

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