How to persist entity in session across controllers?

I’d like to impose that the user choose one entity from the database and then be stuck with it until explicitly released. The idea is to override any chance of any ability of any form to edit any other record for that model until it is explicitly released.

Picture it like this: user is logged in… gets record from database… app saves the id to the session. Any other actions from any and all controllers henceforth will use the id saved in session instead of anything in the url or otherwise. This entity serves as context for other entities, so when editing those other entities, only the ones associated with this one will be available, etc, etc. User opens a new tab hoping to access a different entity and can only access this one. When the user is done with this entity, the controller will call a special action, “done()” which takes the id out from session and now frees the user to select a different entity/context.

I started off doing this in the controller actions. But it’s getting repetitive and tiresome… and the controller logic is muddied by all this extraneous id management (making it even more fun, I’m giving the user the ability to create a new entity and then this new one is the one that gets locked in until released).

My first thought was to move it to the model. Then the controller does’t have to manage the id any more other than releasing it (the idea being that the controller will work with the id passed in the url the first time, but thereafter, will be locked in to that id until its released because the model will end up self-assigning the id after that initial get($id) ).

But then, realizing I want this to be a behavior at least one other model in my app follows, I thought I should make it a behavior.

Anyway. The session can’t be accessed from the model. So that kills that idea.

I briefly thought of moving it to beforeFilter() in AppController, but that has no access to model data.

Any suggestions?

In general, people are doing this sort of thing with URL parameters rather than sessions. For example, for efficiency reasons, I often want to open up 10 edit tabs for different records all at once from an index page, and when things are done in sessions, it messes with my ability to do that. I’m not sure if that’s a complete non-starter for you, or if it only just leaves you with different variants on the same problem…

One of the primary motivations I have is to prevent a user from getting a browser auto-complete, bookmark, or shared url that ends up editing the wrong record. So, in essence, I’m forcing the user to start fresh and pick an entity to work with every time even if they enter a url for an existing record.

I understand wanting to protect users from themselves, but I would hate to use that system. I am constantly using URLs from my browsing history to jump straight to the page I want without having to jump through a bunch of hoops. I always aim to give pages maximally useful titles so that I can type the name of the thing and get right to it. In fact, I think that if I were to go to an autocomplete URL that I expect to get me to a certain page, and it takes me to a different page because I never got around to “closing” whatever I was working on before, I would sometimes not notice this and end up saving changes to the wrong record.

Anyway, I’m not clear on what you’re expecting the model to do here. To use a generic example, if I had selected to work with author id 123, what effect does having that in the session have? If I go to the list of books, it could limit based on that, and if I add a new book, it can use the session id for the author, but these seem no improvement to me over having the author id in the URL.

If I go to an autocomplete edit URL for a book that’s not by that author, does it reject it? Seems counterproductive. Allow the edit to proceed despite this? Then what’s the point of having the session? Allow the edit to proceed and replace the author id that it previously had with the one from the session? Actively harmful for data integrity, so that can’t be what you intend…

I need the app to behave like an actual app on a mobile device. You don’t have urls on mobile devices. No bookmarks. No way to deep link or share states. Everything is modal… based on context selected by the user when starting the app (or returning to it). You can’t really jump around. You always drill down, then exit.

The benefit of that model is that it prevents confusion for dead stupid users who are not savvy about ids and urls. They are presented with a flow to follow and that’s all they can do.

It just occurred to me that maybe I could take the id passed in the url, save it to session, then return this->redirect to the same action… sans id.

So:

  • Action sees an id, it saves it to session and redirects to self without the id
  • Action sees no id, it looks for one in the session and uses that
  • Action sees no id, but finds none in the session either, flashes error and goes back to index

The user would then never see any id in their urls or histories. Everything would look like /authors/new — /authors/edit — /authors/add-book — all without ids. Share most urls with someone and it’s going to be stateless. They will be forced to choose their own context. Sure, some urls might look like /books/catcher-in-the-rye and that will be always the same thing for everyone. But for all the urls related to creating or editing stuff… those would have to be user-defined contexts each every time.

Of course, if I did it this way, then someone like you could still append the id to create a permalink and it would work the way you expect, more or less. Even though your browser would be issuing redirects that might perplex someone like you.

Do you have an author view page with a list of their books on it? To edit one of those, do you have to go to the book view page first (which saves the book ID in the session) and then click edit?

I wonder if using postLink instead of link everywhere would give you the best of both worlds? Maybe not, it gets harder then to tell whether you’re getting the actual edit form posted to you, or just the link to start editing.

1 Like

Yes. The user starts from an index page of some sort and chooses an action on an entity (or else chooses to create a new one). The app has most entity creation and editing performed in several steps as opposed to a single page. So, once this action is initiated, the only way to edit something else should be to save changes or cancel out.

Ideally, the lock would persist even when the browser is closed. But I’m not going to trouble myself with that much overhead.

Post links crossed my mind at one point, but I wasn’t sure how to best leverage them. Then I thought about using ajax to send the id to an action designed to set the id in session before redirecting the user to the form.