I rewrote the title and content 3 times before posting it, I don't find the right way to ask this :P
I have a page that manage a list of notes, I have a CRUD on that page but the items are created and saved in javascript (using knockoutjs).
I create a new note, I add it to the model in javascript and it show up in the page.
The way Im saving the notes to the database is when I add it to the model, I send it via Ajax (async) to the server. So I have my note on screen and in the database really fast.
I send a note without Id to the server and EF will take care of the Id.
So far so good.
Imagine that I add a note but I dont refresh the webpage, so the note is in the database, is in the javascript model too but in the model it doesn't have the id yet.
I make some changes to the note and yeah, I want to update the note in the database... but... how?
I send my note to the server with the changes, but remember, the item still have no Id so I can't say:
Hey EF, give me the note with the ID == xx and we are going to update that note.
The others properties can be changed on the webpage so I have nothing that identifies the note apart from the Id, who doesn't work here.
I tried this:
Send the new note to the server, insert it on the database, retrieve it again (to pick the Id), send it back to javascript and update the object with the Id. So when I edit, I have the Id. Yeah, but the "save" call need to be sync and that destroy the experience.
Any ideas?
EDIT: The sync options is not that slow at the end but there have to be a async way and meh, the thing of "Insert on database", "Retrieve the last item I inserted" and "return back to the client" is a little hackish.
You could return the id of the new record in your asynch call. If you are using jQuery you can subscribe to the "success" callback and as long as your controller returns a JSON with the id of the new record you could update your model on the client side.
Even with this approach, you will need to have a way to identify the item updated on the client side (which is really the root of your question.) For that you can probably generate a random GUID on the client side, send it to the server when saving, and return it to jQuery when returning the ID so that you can identify the correct element to update on the page.
Related
situation: Lets's think about basic process of object creation on a client (with CRUD backend).
Let's imagine that we have two "Create" buttons on a page.
first case:
Clicking on the first button will cause to redirect to /create route, where our form located.
After we fill the form with data, we post it to a backend and it retrieves an id of a newly created object.
second case:
Clicking on the second button will cause to send creation request to the backend, then after we got a new object id, we will be redirected to /edit/:id, where our form located (same form).
After we fill the form with data, we send it to a backend and save already existed object (post by id).
question:
What's the pros and cons of those two cases, when to use each of them?
In the first case you can include the validation of the fields in the time of creation
and you only need to create an insert so one database call.
In the second case you are creating an empty entry that will appear in the grids of an application with no data.
Also if your database has required fields, you have to fill them with default data.
Validation will be more difficult since you need to allow empty ex Mobile in data entry
while phone might be required.
Another problem with this is that that you are basically doing two operations. One if for the Insert of the row and one is for the update of the row
However this methodology is easier to implement the live update of text when typing so any disconnects etc will not lose any data. This methodology is also good for collaboration between two clients using websockets ex inserting the row at the same time.
I've got an issue with a button.
I've got clients, and these all have a number ( Clients:: ClientID). Now I want to make a button in another form and send the active clientID to another application which will use this clientID to display information in that application about that client.
Now I've made a button with the open URL which contains following code snippet:
"http://localhost:12345/showClientFile?clientid=" & Clients::ClientID
When I click the button in viewlayout, the application always (no matter which record I'm in) the same clientID and not the clientID from the record that I'm in. When I check the URL in the browser, it is also that same id constantly. Am I missing something?
If you're on a layout that isn't linked to the Clients table occurrence, then there must be a relationship from whichever TO your layout is linked to to the Clients table. Otherwise you wouldn't see any value for Clients::ClientID.
You say you want to send the "active clientID". How do you, or the system, know what the active clientID is? Is it stored in a global variable, as in $$_ACTIVE_CLIENT_ID, or perhaps a global field, Clients::g_active_client_id? When you can say to yourself, "When I want to know what the active client ID is, I look here," then you know what will need to be done to edit the URL calculation.
"http://localhost:12345/showClientFile?clientid=" & $$_ACTIVE_CLIENT_ID
I have started designing addToCart method as HTTP POST in my RESTful API. This looks good when the client adds to cart a product first time (POST create a new entry on server). But, the same HTTP rule breaks when the client browses through the site and adds the same item again; where we should not create a new entry but only update the quantity of existing item.
Isn't using POST to update resource wrong? What is the way to implement this? or how to interpret this situation.
Note: Client/UI front which uses my api would not remember if its already there on server. Please consider any ecommerce application's addtocart as example.
I think the difficulties here are already present in how you add the original item to the cart.
When you add an item to cart, are you creating a new object (the item)? Or are you modifying an existing item (the cart)? To me it makes more sense to say the latter. POSTing an item seems like it should be reserved for a different situation, when you add a new item to your store.
Conceptually, the cart is then like a vector of all the items in your store, associated with a number (0 for almost all of them). Adding something to the cart means incrementing this number for one of the items, regardless of whether it is already more than 0.
You can use PATCH to send a part object / update to an existing object.
It's based on your model. IMHO a POST is also fine if you are modelling a new intent or cart-operation with it, which can be basically anything.
I have an issue where if a user posts something on my app, and a user with bad internet connection tries to view it, the post is deleted. I think this is because in my code, the client saves the array of posts every 5 seconds or so. Since the client with bad internet connection has an old version of the posts, when they try to view the post, the old version is saved and therefore the new post is deleted. In order to fix this, I need to save columns in an object individually and not affect the new posts column. How do I do this?
You can compare the value in updatedAt, if the local value updatedAt is lower than the one on server, you just wont update it... I think you can do that in cloud code with beforeSave trigger
I'm writing a Catalyst application that's required to have a fairly short session expiration (15 minutes). I'm using the standard Catalyst framework authentication modules, so the user data is stored in the session -- i.e., when your session expires, you get logged out.
Many of the uses of this application will require >15 minutes to complete, so users will frequently submit a form only to find their session state is gone and they're required to log back in.
If this happens I want to preserve the original form submission, and if they log in successfully, continue on and carry out the form submission just as if the session had not expired.
I've got the authentication stuff being handled by an auto() method in the controller -- if you request an action that requires authentication and you're not currently logged in, you get redirected to the login() method, which displays the login form and then processes it once it's submitted. It seems like it should be possible to store the request and any form parameters when the auto method redirects to the login(), and then pull them back out if the login() succeeds -- but I'm not entirely sure of the best way to grab or store this information in a generic/standard/reusable way. (I'm figuring on storing it in the session and then deleting it once it's pulled back out; if that seems like a bad idea, that's something else to address.)
Is there a standard "best practices" or cookbook way to do this?
(One wrinkle: these forms are being submitted via POST.)
I can't help thinking that there's a fundamental flaw in mandating a 15 minute timeout in an app that routinely requires >15 minutes between actions.
Be that as it may, I would look at over-riding the Catalyst::Plugin::Session->delete_session method so that any contents of $c->request->body_parameters are serialised and saved (presumably to the database) for later recovery. You would probably want some rudimentary check of the POST arguments to ensure they're what you're expecting.
Similarly, create_session needs to take responsibility for pulling this data back out of the database and making it available to the original form action.
It does seem like a messy situation, and I'm inclined to repeat my first sentence...
UPDATE:
Whether you use delete_session or auto, the paradoxical issue remains: you can't store this info in the session because the time-out event will destroy the session. You've got to store it somewhere more permanent so it survives the session re-initialization. Catalyst::Plugin::Session itself is using Storable, and you should be able to with something along these lines:
use Storable;
...
sub auto {
...
unless (...) { #ie don't do this if processing the login action
my $formitems = freeze $c->request->body_parameters;
my $freezer = $rs->update_or_create(
{user => $c->user, formitems => $formitems} );
# Don't quote me on the exact syntax, I don't use DBIx::Class
}
...
my $formitems = $c->request->body_parameters
|| thaw $rs->find({$user => $c->user})->formitems
|| {} ;
# use formitems instead of $c->request->body_parameters from here on in
The underlying table probably has (user CHAR(x), formitems TEXT) or similar. Perhaps a timestamp so that nothing too stale gets recovered. You might also want to store the action you were processing, to be sure the retrieved form items belong to the right form. You know the issues for your app better than me.
I would store the form data as some sort of per user data in the model.
Catalyst::Plugin::Session::PerUser is one way of doing that (albeit somewhat hackishly). I would reccomend using the session plugin only for authentication and storing all the state info in the model that stores your user data instead.
And I totally agree with RET's opinion that the 15 minute limit seems really counter productive in this context.
I came across this whilst searching CPAN for something entirely unrelated.
Catalyst::Plugin::Wizard purports to do exactly what you need. The documentation suggests it can redirect to a login page whilst retaining the state of the previous action.
NB: I haven't used it, so can't vouch for its effectiveness.
In the end, we ended up grabbing the pending request (URL+params) in the auto(), serializing and encrypting it, and passing it via a hidden form element on the login page. If we got a login request with the hidden element populated, we decrypted and deserialized it and then redirected appropriately (making sure to pass through the standard "can this user do this thing" code paths).
You could always have some javascript on the client that keeps the session from expiring by making a small request every few minutes.
Or you could have AJAX check for an active session before posting the form and presenting the user with a new login box at that time if needed.