# Rails, sessions, and associations?

**URL:** <https://www.ruby-forum.com/t/rails-sessions-and-associations/92746>\
**Category:** Rails\
**Created:** [April 23, 2007, 6:46pm UTC](https://www.ruby-forum.com/t/rails-sessions-and-associations/92746 "2007-04-23T18:46:29Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Antiarc](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/e79b87/32.png) [@Antiarc](https://www.ruby-forum.com/u/Antiarc)\
**Post date:** [April 23, 2007, 6:46pm UTC](https://www.ruby-forum.com/t/rails-sessions-and-associations/92746/1 "2007-04-23T18:46:29Z")

</div>

I’m running Rails 1.2.3, as a precursor.

I’ve recently discovered some odd behavior in how Rails treats objects  
saved in the session and its associations.

* * *

class Foo \< ActiveRecord::Base  
has\_one :bar  
has\_one :barfoo  
end

foo = Foo.new  
foo.build\_bar  
session[:myfoo] = foo

_POST_

foo = session[:myfoo]  
foo.new\_record? -\> true  
foo.bar.nil? -\> false

foo.save  
foo.build\_barfoo  
foo.barfoo.nil? -\> false  
foo.barfoo.new\_record? -\> true  
session[:myfoo] = foo

_POST_

foo = session[:myfoo]  
foo.new\_record? -\> false  
foo.barfoo.nil? -\> true # This is the problem!

* * *

It looks like what happens is that if you store an object in the  
session, associations get stripped from the object before  
serialization IF object.new\_record? == false. This is good, most of  
the time, as it keeps the session size down. However, when the  
association is unsaved, this is bad. I’m doing a process like so:

Object created -\> association #1 created -\> object and association  
updated with form data and stored in the session -\> preview is  
rendered -\> on confirm, object in session is saved.

Later,

Object loaded from DB -\> association #2 created -\> association #2  
updated with form data -\> object stored in session -\> preview rendered  
-\> on confirm, should save the object and its association, but the  
association is now nil.

Is this a bug? Should unsaved associations not be stripped, or am I  
using the wrong design pattern here?

My workaround was to store the association object in the session and  
to manually reassociate it with the object on each page load, but  
that’s really kludgy and I’d prefer a more elegant solution if  
possible. This feels like a bug, though, and it caused me to lose  
multiple hours tracking it down - it is certainly not intuitive in the  
slightest.

---

<div class="post-metadata">

**Author:** ![Antiarc](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/e79b87/32.png) [@Antiarc](https://www.ruby-forum.com/u/Antiarc)\
**Post date:** [April 23, 2007, 7:32pm UTC](https://www.ruby-forum.com/t/rails-sessions-and-associations/92746/2 "2007-04-23T19:32:07Z")

</div>

Antiarc wrote:

> Object loaded from DB -\> association #2 created -\> association #2  
> updated with form data -\> object stored in session -\> preview rendered  
> -\> on confirm, should save the object and its association, but the  
> association is now nil.
> 
> Is this a bug? Should unsaved associations not be stripped, or am I  
> using the wrong design pattern here?
> 
> My workaround was to store the association object in the session and  
> to manually reassociate it with the object on each page load, but  
> that’s really kludgy and I’d prefer a more elegant solution if  
> possible. This feels like a bug, though, and it caused me to lose  
> multiple hours tracking it down - it is certainly not intuitive in the  
> slightest.

Everything stored in session will be serialized, so yes, the design is  
incorrect. You should save the record id in the session instead of  
storing the ActiveRecord object in a session O\_O.

---

<div class="post-metadata">

**Author:** ![Antiarc](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/e79b87/32.png) [@Antiarc](https://www.ruby-forum.com/u/Antiarc)\
**Post date:** [April 23, 2007, 8:44pm UTC](https://www.ruby-forum.com/t/rails-sessions-and-associations/92746/3 "2007-04-23T20:44:38Z")

</div>

Wai T. wrote:

> Everything stored in session will be serialized, so yes, the design is  
> incorrect. You should save the record id in the session instead of  
> storing the ActiveRecord object in a session O\_O.

Ok, I may be approaching this incorrectly then. I want to achieve the  
following:

a) Create a new object (Foo) that may be saved to the database at a  
future point. If the user abandons the process, then nothing should be  
saved to the database.  
b) Be able to create association objects (Bars and Barfoos) to be  
associated with the object, and then possibly saved at some point in the  
future. If the user abandons the process, the associations should not be  
saved.

My process so far has been:

- Create a Foo, set some properties based on form input, and put it in  
the session.

- Add any Bar associations and set their properties via form input

- Save the Foo to the session, which serializes its Bar as well.

- Preview the Foo with its Bar association

- If we decide to commit the changes, Foo (and its Bar) are read in from  
the session, validated, and saved.

- At some point later, a user may load a Foo from the database and want  
to attach a Barfoo to it. build\_barfoo is called, and some properties  
are set on both the Foo and the Barfoo from form input.

- The Foo (and its associated Barfoo) should be saved to the session  
(this is where it fails)

- The user may then preview the results

- If the user chooses to commit the changes, the Foo should be saved  
(UPDATE) and its associated Barfoo should be saved (INSERT).

How else could I achieve this workflow?

---

<div class="post-metadata">

**Author:** ![Antiarc](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/e79b87/32.png) [@Antiarc](https://www.ruby-forum.com/u/Antiarc)\
**Post date:** [April 23, 2007, 10:23pm UTC](https://www.ruby-forum.com/t/rails-sessions-and-associations/92746/4 "2007-04-23T22:23:55Z")

</div>

For situations like this, we always save to the database. We’ll use  
before\_filters to load the data from the database on each request…  
Every  
night we run a process to purge incomplete records from the database by  
checking the created\_at date We’re usually wiping out records that are  
7  
days old or more just to be safe. Using a status flag on the table lets  
me  
control what “state” the object’s in, and I can have validations that  
only  
get fired on certain states, allowing me to save records at any point in  
the  
process.

If that idea doesn’t sit well with you, consider the following:

1. If a user’s browser crashes, they lose their work. With the above  
method,  
they could come back and finish.
2. Marshalling to the session is prone to problems and can be a  
performance  
problem.

Just my .02. I’m sure that lots of folks will disagree with my  
approach.

---

<div class="post-metadata">

**Author:** ![Antiarc](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/e79b87/32.png) [@Antiarc](https://www.ruby-forum.com/u/Antiarc)\
**Post date:** [April 23, 2007, 11:37pm UTC](https://www.ruby-forum.com/t/rails-sessions-and-associations/92746/5 "2007-04-23T23:37:34Z")

</div>

## I ended up going with this solution (heavily simplified, of course!):

class Foo  
has\_one :bar  
has\_one :barfoo  
end

foo = Foo.new params[:foo]  
foo.build\_bar params[:bar]  
session[:myfoo] = foo

_post to preview_ -\> _confirm save_

foo = session[:myfoo]  
if foo.save then  
session[:myfoo] = nil  
end

* * *

foo = Foo.find params[:id]  
foo.build\_barfoo params[:barfoo]  
session[:myfoo\_id] = foo.id  
session[:myfoo\_barfoo] = foo.barfoo

_post to preview_ -\> _confirm save_

foo = Foo.find session[:myfoo\_id]  
foo.barfoo = session[:myfoo\_barfoo]  
if foo.save then  
session[:myfoo\_barfoo] = nil  
session[:myfoo\_id] = nil  
end

* * *

This seems to work well. Only unsaved objects are persisted in the  
session, which gives me pretty good concurrency-proofing, doesn’t force  
me to deal with the marshaling quirks of an saved object with unsaved  
associations, and doesn’t leave cruft in the database.

It isn’t browser-crash-proof, but this is “cheap data” that doesn’t  
really need to be protected against crashes.
