Challenges with RJS and Redirection
by Sean Cribbs
There are always serious conceptual challenges with building a large system, especially when you want to keep the responsibilities of each component clear and with as few side-effects as possible.
There’s one controller action in the not-so-stealth-anymore project
(GiftLasso) I’m working on that begins multiple workflows. Naturally,
we’ve been using Bruce Williams’ wonderful in_context
plugin for
most of these issues. The main point of this action is to create (or
find) a model — I’ll call it model A — that needs to be present for
the subsequent action. Once this first model is created, we redirect
to the new
action of the next controller so that the user can input
some information and then create the associated model (Model B). Our
application is CRUD-focused but doesn’t use REST as of yet. In the
future, I’d prefer to create model A as we’re creating model B, but
the separation works well for now and is conceptually cleaner.
That pattern worked very nicely and cleanly until we wanted to add a
little Ajax in the mix. The idea was to add pop-over boxes so that
the user could stay in the same page, browsing through lists of Model
A, and create instances of Model B as needed. However, since the
lists of Model A are loaded through an external web service, and not
necessarily created until someone tries to create a Model B, we need
to go through Controller A’s create
method as previously described.
“Ok,” I thought, “we’ll just let the Ajax request follow the redirection.” Unfortunately, when redirected, Prototype (or Firefox, I’m not sure which) doesn’t maintain those special headers that indicate the request is from Ajax. So the response I got back was the default HTML, complete with layout! So much for intuitive!
Then I thought, “Maybe the page.redirect_to
method is the right
way.” No luck, that actually redirects the whole browser page since
it sends a window.location.href = "your url"
, which is exactly what
we don’t want.
In the end the solution I came up with was to create a new Ajax request, like so:
This creates quasi-redirection behavior I was looking for. Too bad it’s not the default!
There were a couple other things that I learned along the way. The
create
action for Controller A previously mentioned used to look
like this (after its first refactoring):
However, I discovered that most of the delegated actions were really just loading Model A from the session or parameters, and then redirecting based on whether it was found and saved or not. Obviously this pattern wouldn’t work for RJS/Ajax.
So I abstracted out the generated flash messages and redirection URLs into hashes like so:
Blocks/procs/lambdas are wonderful for abstraction and refactoring. Make use of them! With the above, I could easily handle both the plain and the Ajax-based “redirection”.
Of course, all of this is a distillation of what I did for the actual thing.
If you’re curious about what GiftLasso is, fear not, we’ll be releasing very soon!
p.s. u.s.w. is German, und so weiter, meaning “and so forth”.