The "store locator problem"

I’m not sure what Rails elements come into play here, so I’m just
calling this the “store locator problem”. Bear with me…

Assume I have a database-backed Store model. And that it has a
“locator” method that returns a list of NEW store objects – NOT YET
SAVED IN THE DB – that are near a given zip code. (Why? Because the
stores are found via an external service and we don’t want to clog our
db with records we’re never going to use.)

class Store < ActiveModel::Base

Return a (possibly empty) list of instantiated but not yet saved

Store objects
def self.locate(zip_code)

end

end

I’m trying to figure out how best to implement the following
interaction:

  1. user visits a page. the page contains a form prompting for a zip
    code.

  2. user enters zip code and presses “find stores” button

  3. STILL ON THE SAME PAGE, the user is presented with a list of matching
    stores with a “choose this one” button (or link) next to each one.

  4. when the user clicks on “choose this one”, that store is saved to the
    DB (and a bunch of other stuff happens)

  5. the user is redirected to /stores/nnn, where NNN is the id of the
    newly created store.

There’s two catches

  • I want to implement this first version using NO javascript. (I’ll
    write unobtrusive JS later…)

  • I want all the above steps to be rendered in a partial (e.g.
    app/views/stores/_locator.html.erb), so I can reuse it in more than one
    place in my system.

I have just about everything working: the stores/_locator partial calls
stores_locator_path => StoresController#locate(zip) =>
Store.locate(zip). Then StoresController calls render(:partial =>
stores/_found_stores) to display the list of stores in place.

My one problem: the StoresController#locate method needs to know where
the request came from, so it knows what page to render (see step 3
above).

Is there a clean way to do this? (I can imagine passing something in
the params list, but that seems messy.) Or is there a better approach
overall?

Thanks.

  • ff

Update: After mulling this over for a few hours, I have concluded that
I’m asking two distinct questions:

Q1: If I have a page that contains a partial that contains a form that
invokes an action in MyController, how do I return the results to the
original page?

A1a: I could (somehow) arrange to have the form emit the
controller/method combo that would get me back to the original page,
and, after MyController has done its thing, call
render(‘controller/method’) to get back to it.

A1b: I could use redirect_to env[“HTTP_REFERRER”], but unlike
render(…), that’s a separate transaction, so I’ll need to store my
temporary Store objects somewhere. See Q2.

Q2: Where can I squirrel away unsaved Store records across transactions
(e.g. if I use redirect_to as per A1b above)?

A2a: Use the session hash. (This feels really wrong)

A2b: Stop fighting Rails and save the Store records. Create a
StoreLocator model, make it responsible for creating Store records and
pruning the ones we don’t use. Or something like that.

Any better suggestions?

If you could use a tiny bit of JS in the form…

  1. The new action: Render a form with the zip code and an empty list
    of stores.

  2. The create action: Form submits the zip code, but no store data.
    Take the zip code, find the stores, and render the new action again,
    this time with the list of stores. Use a small set of hidden variables
    to send the selected store data back. Use a small bit of JS to set the
    hidden variables to the values of the store selected.

  3. The creation action: Form submits the zip code and the hidden
    variables, which now contain the values of the store needed to create
    the store.

If the list was small, I suppose you could have a bunch of hidden
variables, one ‘set’ for each store. Workable, but a little ugly and
perhaps has limits.