Reputation: 45
My Sinatra webapp has a list of articles which can be deleted by the users. I've added a jQuery animation to make the deleted articles fade away before the actual (DB) deletion is carried out by a Sinatra route. The code is elementary:
# script.js
$(".lnk-delete").click(function()
{
var id = $(this).closest("article").attr("id");
$("#"+id).fadeToggle(1000);
});
# app.rb
get '/delete/articles/:id' do
Articles.get(params[:id]).destroy
redirect to('/')
end
The problem is, the code reroutes to the same page, which is now unnecessary since the deleted article is no longer showing. Not only the reroute generates unnecessary load, it also brings the user back to the top of the page (making the experience confusing and annoying).
I have looked around, tried returning HTTP codes, tried halt(ing), tried the request.xhr function and anything else I could find online, all to no avail...
Is there a way to make the route "not route", i.e. execute the db.destroy and leave the actual page "unrefreshed"?
The following code, a slightly modified version of @exobrain's answer, solved my problem.
# script.js
$(".lnk-delete").click(function(clicked) {
clicked.preventDefault();
var id = $(this).closest("article").attr("id"); $("#"+id).fadeToggle(1000);
$.get($(this).children("a").attr("href"));
});
Three things changed in my original code:
preventDefault
to the script so as to prevent the link being followed;get
;Here's the code:
# app.rb
get '/delete/articles/:id' do
Articles.get(params[:id]).destroy
end
As a note to beginners (as myself), this get
route is inconsistent with best practices. It should be a delete
route. I'll fix that, eventually.
Thanks, @exobrain & @Amadan, for the answers.
P.S.:
Fixed the get
route. All it took was changing
$.get($(this).children("a").attr("href"));
to
$.ajax({ url: $(this).children("a").attr("href"), type: "delete"});
and then get '/delete/articles/:id' do
to delete '/delete/articles/:id' do
on the actual Sinatra application.
Upvotes: 1
Views: 249
Reputation: 12251
Instead of a redirect, use a halt
at the end of the route with the correct status code. You should also get rid of that GET as you've been advised.
get '/delete/articles/:id' do
Articles.get(params[:id]).destroy
redirect to('/')
end
becomes
get '/articles/:id' do
# get the article here
end
delete '/articles/:id' do
Articles.get(params[:id]).destroy
halt 200
# I'd also return a representation of the deleted article
# or perhaps it's ID
# but maybe that's just me
end
HTTP has verbs for a reason. Don't use $.get
, use $.ajax
and pass it the correct verb i.e. DELETE. See Type in the link.
Notice that the verb no longer needs to be in the URL as well.
Upvotes: 0
Reputation: 133
It's a bit odd to be using a get
request to delete a resource, but none-the-less, you can do this using ajax. I'm assuming .link-delete
is an a
tag, and has a href
attribute pointing to the Sinatra endpoint. The following code will stop the link from being followed through by the browser (preventDefault
), then perform an AJAX get
request to the url pointed to by the link. When the request completes and returns, the fadeout is performed in the callback.
$(".lnk-delete").click(function(e) {
e.preventDefault();
$.get(this.href, function() {
var id = $(this).closest("article").attr("id");
$("#"+id).fadeToggle(1000);
}
});
Upvotes: 0
Reputation: 198408
If you're submitting to /delete/articles/...
via AJAX, the actual page will remain unrefreshed. (You have not shown the submit code.) You can simply return ""
from your controller instead of the redirect for a blank body.
If you're not using AJAX, then the fadeout is superfluous; you will need that redirect.
Upvotes: 1