New comment w/ajax - owner_id not in request parameters until page is refreshed - ajax

I have a comments form which attaches to the "revision" of a "section". If no revision exists, an empty one is created. The add comment form is loaded with ajax. The issue, is that if several comments are added without refreshing the page, several empty revisions are created. This causes havoc in certain edge cases.
I request a new add comment form with ajax every time the add comment button is hit. However, Rails thinks there's no new information and serves 304 not modified. There is new information - the comment form on the second request should have a populated "owner_id" which is the id of the empty revision created by the first comment.
I'm positive the owner_id population works as refreshing the whole page fixes the issue. I used to think this was a server cache issue but looking at the parameters of the request, owner_id is missing until the page is refreshed.
Update: I added expire_now() to the new action on comments controller and it's now serving a 200 response but the contents still have no owner_id.
Another update: Looking in the console, the parameters of the request don't include the owner_id. Refreshing the page then requesting the form suddenly includes the owner_id in the parameters.

I'm still not sure about the details on this, but an ajax request is different from a page request in a number of ways. For example, controller code is not updated when just requesting a view with ajax. In my case, there is also difference of not having owner_id as a populated parameter for ajax views.
In the new action on the comments controller, I had to manually query the section to see if there was a revision, and if so, set the owner_id with the revision id.
def new
# precaution against creating multiple empty revisions if user adds multiple comments without refreshing page
if params[:owner_id].nil?
revision = #section.send(params[:snip_type]).first
unless revision.nil?
#comment.owner_id = revision.id
end
end
end

Related

note passed in as part of CreateCheckoutRequest, but where to on the payment page or the dashboard to view them?

I am using nodeJs, and I have passed in note inside CreateCheckoutRequest, however, i am not seeing the note showing on the payment page url generated by createCheckout or the dashboard page.
My ultimate goal is our frontend can pass in the phone number as note to sqaure-connect, so that we can view the phonenumber from our dashboard once the customer completes an order
Tried to look at old transactions, since we didnt use note, didnt see any note.
const checkout = SquareConnect.CreateCheckoutRequest.constructFromObject({
idempotency_key: 'sample_key,
order: orderRequest,
redirect_url: redirect_url,
ask_for_shipping_address: true
note, // need to see it from dashboard once the user completes an order
});
When adding a note to a CreateCheckout request, it will end up on the tenders->note field of the associated transaction. To clarify, once the customer has paid on the checkout page, it should redirect to your web page (based on your redirect_url field that you passed to CreateCheckout originally). From there, the url will contain a parameter called transaction_id. You can then use this id to retrieve the transaction and digging into it to find the note (transaction->tenders[0]->note). In this particular use case, there will always only be one tender since Checkout doesn't allow multiple tenders.
Now, to actually answer your question: the tender note will be displayed as the main text you see when you view your transactions. So when you login to your Square Dashboard and click Transactions, in the main list, the "header" will be whatever the tender note was.

Restful URL After Insert

I am new to RESTful URLs and I have a general question. Let's say I have a URL that I use to retrieve student records: somesite.com/students/123 which retrieves the details for the student with ID 123.
I then do the following to load an empty form for adding students: somesite.com/students/0 where zero indicates that I want to display an empty student detail form (or somesite.com/students/new).
The question I have is that after I add a student record I get back a new Id. However, if I add the record using AJAX without submitting and refreshing the page, my URL still shows somesite.com/students/0. If a user clicks refresh then the empty form is displayed again rather than the new student record.
How should that be handled?
It's not like your server can't respond to AJAX requests, right?
All you need to do is send back the newly generated ID, and then:
Use window.location = 'new_url' to redirect the user
Or even better, use history.pushState() (if available) to change the URL without any redirection (and reloading) happening at all
One thing that seems off, though, is the use of GET page/students/0 to get an "empty record", or, as I understand it, a "template" for new records. I don't think that's how RESTful services work, but then again, I'm not an expert in REST services.

Dynamically add form to formset in Django and submit with AJAX

I have read a lot of answers relating to how to dynamically add forms to an model formset in Django and can successfully implement that. However, I would now like to submit the formset with AJAX. This is mostly working now but I have an issue that I can't find a solution to in any other answer:
If you dynamically add a form to the formset, you give it a new form id number that is one larger than the maximum the form currently has and you also increment the management TOTAL_FORMS count by one. The newly added form then saves successfully as a new object.
I am trying to submit by AJAX so the user can continue editing without having the page refresh. The formset saves fine but any dynamically added forms are now existing objects. To account for this I need to increment the INITIAL_FORMS count on the management form when the save is successful. Easy enough. However, I've also realised I need to give the newly created objects an ID since they now exist in the database.
How can I get my view to tell me the ID of the new objects in its response to the AJAX call? Or is there a better way of looking at this?
Django forms and formsets are intended for classic browser-based posting of data. Though they can definitely be made to work with Javascript, the more you want to part from the normal behavior, the more complex it gets.
Depending on your requirements, you might start thinking about dropping it and switch to Javascript + REST endpoint. Of course, if you need progressive enhancements and you are required to have it work without javascript, that's not an option.
In any case, you want to have a customized view for posting from JS, so that you can get the result back and parse it easily in your AJAX handler. Probably some JSON.
There are several approaches you could take.
Have your AJAX send data to a different URL. This is pertinent if you have an API or are planning to build one at some point. So your form, when submitted normally, will do its old-style processing but your AJAX will talk to the API endpoint instead.
For instance, your form send to https://example.com/myform, but your Javascript code talks to REST api at https://example.com/api/v1/mymodel/ (sending PUT, POST and DELETE requests as appropriate).
Or if you don't have an API and building one seems overkill, you may just alter your view so it formats its output differently depending on whether the data is being submitted in the regular way or using AJAX.
You'd go about it like this:
class MyFormView(.....):
def render_to_response(self, context, **kwargs):
if self.request.is_ajax():
return self.render_to_json(context, **kwargs)
return super().render_to_response(context, **kwargs)
def render_to_json(context, **kwargs):
data = {
# see below!
}
return HttpResponse(
content=json.dumps(data).encode('ascii'),
content_type='application/json',
)
This is just an outline. You need to ensure is_ajax will detect it properly (see django doc). And you need to properly build data from context: extract the things you want to send back to your JS code and put them in the dict.
You will find it's manageable if you just do this for one, maybe two views in your project, but very quickly you'll want to have a small API instead, especially given how easy it is to build one with packages such as Django REST framework.
In your view, where you save the object, AFTER the save, the object.id will contain the new id for the object, which you can return via json or however you want in your ajax response, and then yes you will need to fill that into the formset row so that it will be submitted the next time.
One thing you have to watch out for is that django expects all existing rows to be at the top of the formset, and any new rows to be at the bottom. Otherwise, the formset save will complain about missing id's. So if you're doing any kind of sorting in your javascript, you can't do that.. unless you do quite a bit of fixing of all the field names etc in the formset. The formset code uses the numbers in the management form to determine which rows to insert and which rows to update, it does not do it on the basis of whether or not an id is present. Unfortunately...

How rails form instance works?

I have these two methods, show and create.
def show
#article = Article.find(params[:id])
#comment = Comment.new
#comment.article_id = #article.id
end
def create
#comment = Comment.new(comment_params)
#comment.article_id = params[:article_id]
#comment.save
redirect_to article_path(#comment.article)
end
Show method displays my comment form.
In the show method why do we create a new instance of Comment and also associate the comment
instance to an article id.
Create method actually handles the submission of form.
In the create method, again i am creating a new comment object and again associating the comment's article_id.
My whole questing is why were repeating these things?. Why do I have associate my comment form with article_id when I am displaying it and again I am repeating the steps while submitting the form too.
This repetition could be avoided if you keep those resources nested and build the form as:
<%= form_for(#article, #article.comments.build) do |f| %>
Hope this helps! :)
The reason that you initialize a comment both times is because the user's browser only sees the html form - it doesn't have a concept of a Comment - and because each request to a Rails application is independent - nothing is persisted in the application between requests:
When the user requests the show page for an Article, the request is handled by the application something like this:
The controller creates a new Comment object (in memory).
The form_for helpers in the view build a form from that Comment.
The html for the show page is sent to the user's browser.
At this point the application has done everything it needs to serve this request, so the temporary Comment object is deleted.
When the user submits the form, the values that were entered are sent to the application in the comment_params and the application handles this request like this:
The controller creates a new Comment object (again in memory), but initializes it with the data that the user sent through in comment_params.
The controller saves the Comment - this stores the Comment in the database so it can be loaded later.
The controller redirects back to the show page.
Saving to the database is the main way that the application can persist things between requests - objects in memory only exist while the request is being processed.

Proper way of deleting records with Codeigniter

I came across another Stackoverflow post regarding Get vs Post and it made me think. With CI, my URL for deleting a record is http://domain.com/item/delete/100, which deletes record id 100 from my DB. The record_id is pulled via $this->uri->segment. In my model I do have a where clause that checks that the user is indeed the owner of that record. A user_id is stored in a session inside the DB. Is that good enough?
My understanding is, POST should be used for one time modification for data and GET is for retrieving regards (e.g. viewing an item or permalink).
You really ought to require a post request when deleting. In CodeIgniter this could be as simple as checking $this->input->post('confirm')
Part of the justification is you don't want data changed on a get request. Since you said you are requiring the person be the owner, there still is the problem that some one puts an image with the source being http://domain.com/item/delete/100 Using post isn't a cure-all as you can do post requests from javascript so it would still be possible for a malicious user to create the delete request if you aren't properly filtering input.
I should admit that I'm a bit of a purist and just feel requiring post is the right way. Its how the standards were written (okay you could argue it should be a DELETE request but browsers typically don't support them) and in other cases you really need to use them (there have been cases of web crawlers deleting pages).
If you want to have the delete link be http://domain.com/item/delete/100 then you could display a confirmation message with a form that does a post action as confirming the deletion.
I hope this helps,
Bill

Resources