Forum: Ruby on Rails Multiple screens before save called

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
443a308e12ba2a3082fb6170ca94c2ef?d=identicon&s=25 Ed Wg (ewildgoose)
on 2005-12-20 21:54
(Received via mailing list)
Is there a clever rails way to chain multiple forms together to collect
all the info that I need before finally calling "save"?

For example consider an app which needs to create a "Order" object which
is tied to a "Contact" object which may or may already exist.  Lets
pretend we don't want to save the order to the DB until the contact info
is known and both objects must be saved atomically.

We have a form for editing Orders, and a Form for editing Contacts.  We
call the Orders form first and obtain the info, now I want to stash the
detail somewhere while I go and obtain the Contact data.  What is a good
way to serialise that data while we call the Contact form?  Lots of apps
like to stuff it in as a serialised hidden field so that you don't have
problems with multiple sessions at the same time - how might we go about
this in Rails?

Ed W
4bd34a2216dc8bdbf1f017f64e4d59e8?d=identicon&s=25 Kyle Maxwell (Guest)
on 2005-12-21 02:58
(Received via mailing list)
You could save it in the session or flash.
443a308e12ba2a3082fb6170ca94c2ef?d=identicon&s=25 Ed Wg (ewildgoose)
on 2005-12-21 09:14
(Received via mailing list)
Kyle Maxwell wrote:

>You could save it in the session or flash.
>
>

But that's going to be a problem when you have a user logged in and they
open up several windows to your server, isn't it?

Ed W
88d3bfc2c18b9e73d9180aaac8c1b321?d=identicon&s=25 Patrice Neff (Guest)
on 2005-12-21 10:08
(Received via mailing list)
El 20/12/2005, a las 02:59 PM, Ed W
escribió:
> Is there a clever rails way to chain multiple forms together to
> collect all the info that I need before finally calling "save"?

How about marshalling your objects using YAML and putting them into a
hidden form field. Have never tried it, but ought to work.

Patrice_______________________________________________
Rails mailing list
Rails@lists.rubyonrails.org
http://lists.rubyonrails.org/mailman/listinfo/rails
4bd34a2216dc8bdbf1f017f64e4d59e8?d=identicon&s=25 Kyle Maxwell (Guest)
on 2005-12-21 10:29
(Received via mailing list)
On 12/21/05, Ed W <lists@wildgooses.com> wrote:
> _______________________________________________
> Rails mailing list
> Rails@lists.rubyonrails.org
> http://lists.rubyonrails.org/mailman/listinfo/rails
>

Not if you're smart about it.

--
Kyle Maxwell
Chief Technologist
E Factor Media // FN Interactive
kyle@efactormedia.com
1-866-263-3261
36feb4959db6ab8259a44962f0fa761f?d=identicon&s=25 Jens Kraemer (Guest)
on 2005-12-21 10:35
(Received via mailing list)
On Wed, Dec 21, 2005 at 08:13:57AM +0000, Ed W wrote:
> Kyle Maxwell wrote:
>
> >You could save it in the session or flash.
> >
> >
>
> But that's going to be a problem when you have a user logged in and they
> open up several windows to your server, isn't it?

To save you from having to store all the form data in a hidden field,
you could implement a 'session inside session' approach, i.e. store
your form data under a unique key in the user session.

Each time a user submits the first of your forms, a new key has to be
generated and kept in a hidden field on all following pages.  The key
now allows you to retrieve the correct order object from the user's
session, even if the user has opened more browser windows to your app.


Jens
443a308e12ba2a3082fb6170ca94c2ef?d=identicon&s=25 Ed Wg (ewildgoose)
on 2005-12-21 17:38
(Received via mailing list)
>To save you from having to store all the form data in a hidden field,
>you could implement a 'session inside session' approach, i.e. store
>your form data under a unique key in the user session.
>
>Each time a user submits the first of your forms, a new key has to be
>generated and kept in a hidden field on all following pages.  The key
>now allows you to retrieve the correct order object from the user's
>session, even if the user has opened more browser windows to your app.
>
>

How does this compare with simply marshaling the data and putting that
in a hidden text field on the form?

Arguably the data is harder to forge if you leave it in the session, but
I'm thinking that the validation is all done at the end and if there are
problems we popup the correct screen for the user to correct (rinse and
repeat until we are happy)

Any pros/cons to either technique?

Thanks

Ed W
4bd34a2216dc8bdbf1f017f64e4d59e8?d=identicon&s=25 Kyle Maxwell (Guest)
on 2005-12-21 21:09
(Received via mailing list)
On 12/21/05, Ed W <lists@wildgooses.com> wrote:
> >
>
> Thanks
>
> Ed W
>
> _______________________________________________
> Rails mailing list
> Rails@lists.rubyonrails.org
> http://lists.rubyonrails.org/mailman/listinfo/rails
>

I would use single table inheritance to achieve the results you
desire.  Make a base class called EmptyOrder, then an inherited class
called PartlyCompletedOrder, then a class inherited from
PartlyCompletedOrder called CompletedOrder.  EmptyOrder has all of the
instance methods you wish to have in this class, as well as a method
called to_class, which takes a class name as an argument, and attempts
to type cast the row to that class.  PartlyCompletedOrder has some
validations, and CompletedOrder has yet more validations.  As should
be apparent, you don't need exactly three classes in this system,
2...n will work.

My one concern with this system is the associations.  They will have
to be particularly complex, as you may need to specify an association
in the EmptyContact class for each class in the Order hierarchy, and
vice versa.  I haven't had to use this technique for multi-model forms
yet.  Let me know how it goes, should you choose this route.

--
Kyle Maxwell
Chief Technologist
E Factor Media // FN Interactive
kyle@efactormedia.com
1-866-263-3261
443a308e12ba2a3082fb6170ca94c2ef?d=identicon&s=25 Ed Wg (ewildgoose)
on 2005-12-23 00:30
(Received via mailing list)
>To save you from having to store all the form data in a hidden field,
>you could implement a 'session inside session' approach, i.e. store
>your form data under a unique key in the user session.
>
>Each time a user submits the first of your forms, a new key has to be
>generated and kept in a hidden field on all following pages.  The key
>now allows you to retrieve the correct order object from the user's
>session, even if the user has opened more browser windows to your app.
>
>

I have thought about this a bit more and I like the idea.  Actually this
technique could be useful in lots of other areas, for example where you
want to track the "redirect to previous" location, it would obviously be
nice if this didn't go wrong just because you were editing two things in
seperate browser windows.

The biggest issue I see is that the session is going to fill up with
crud data?  Assuming that the users in question are using the system day
in and out then the session isn't going to expire so the session will
eventually fill up with huge amounts of dead data every time a
transaction is aborted.

Is there a smart way to handle this?  I can imagine making the session a
hash and storing a "last used" time as well as the object.  Then perhaps
every time we access the session we need to scan through for old data.
It seems to incur a bit of overhead, but it's not obvious how else to do
it?

Is is possible to build something which can "walk" every session on a
timed basis and examine all the objects and remove anything which has
expired?

Any other suggestions?

Ed W
6e672922c21a5298f2a666ecb1c11d7c?d=identicon&s=25 Philip Edelbrock (Guest)
on 2005-12-23 00:45
(Received via mailing list)
Ed Wildgoose wrote:
>
> transaction is aborted.
>
> Any other suggestions?

We just submit the form along and create a new (hidden) form on each
page in the track.

I.e., in the controller:

  @order = Order.new(params[:order])
(now you can validate it, whatever, but not save it until they commit
the order in another method)

in the pages in the track:

<form action="error" method="post" name="order_data">
  <% @order.attributes.each do |column| %>
   <input type=hidden name="order[<%= column[0] %>]" value="<%=
column[1] %>">
<% end %>

Notice the action is invalid.  We have two buttons, edit and submit.  JS
overrides the action name and submits for us either backwards or
forwards in the track.  With no JS support they go to the error page.

BTW- Be careful what you store on the web server if you are subject to
Visa or MC audits.  You are not supposed to store credit card numbers on
a public facing server, for example. And, you never should store CSC
card #'s (those 3 or 4 digits on the back of the card).  I noticed the
Rails book uses examples where they store credit card numbers and such,
which can be a no-no in many cases.

Oh, and be careful what method you use to store sessions.  We switched
to storing sessions in the SQL backend, and things broke.  We had to go
back to files.  This seems to be especially true for sessions which
store larger chunks of data.


Phil
This topic is locked and can not be replied to.