In a brand new Rails application with a scaffolded RESTful model, the generated delete code looks like this:
class BeersController < ApplicationController
# DELETE /beers/1
# DELETE /beers/1.xml
def destroy
@beer = Beer.find(params[:id])
@beer.destroy
respond_to do |format|
format.html { redirect_to(beers_url) }
format.xml { head :ok }
end
end
end
If a user tries to delete the same Beer twice (maybe a quick double-click, or actions in two different browser tabs) they will get a RecordNotFound error resulting in a 404 page. This is a pretty unfriendly experience; it seems like it would be better to complete the redirect back to beers_url
regardless, possibly with a flash
error, since there isn't really anything the user can do about the second delete failing.
An alternative approach is to act like the delete succeeded anyway with something like this:
def destroy
@beer = Beer.find_by_id(params[:id])
destroyed = @beer.try(:destroy)
respond_to do |format|
format.html { redirect_to(beers_url) }
format.xml { destroyed ? head(:ok) : head(:not_found) }
end
end
I can understand the desire for a hard 404 error in the API use-case, but it's harder for me to justify for a web application. Can anyone provide a good reason why we should throw a scary error at the user in the name of RESTfulness?
(This question isn't particular to Rails, but I don't know how other frameworks handle this case out of 开发者_开发技巧the box).
UPDATE: It turns out I was wrong: https://stackoverflow.com/a/24713946/14731
Previous answer:
HTTP DELETE
is an idempotent operation. Invoking it multiple times consecutively must result in the same behavior as the first. Meaning: you shouldn't return HTTP 404.
I don't think you should ever throw the error at the user for the sake of holding up some standard - especially if this is a consumer facing app (as opposed to B2B). But you also shouldn't make your api change its status code just for this one situation. The resource doesn't exist anymore; so a 404 is a proper response.
I think there is a path of least (or lessor - is that even a word???) resistance here. I haven't explored ruby yet so I can't provide any usable implementation; but I'm somewhat experienced with web apps using html/css/js.
If there is some legitimate problem with users clicking a button twice; why not set up the button so that it disables when the request is submitted, and re-enables once the conditions are proper (request has come back)? In other words, avoid the if(this very specific situation) logic by making it impossible to get into the situation you're seeing. I'm assuming ruby has something specifically for handling requests and adding function handlers for different status codes; or at least non-200 status codes.
Rails scaffold code is a suggestion at best. Your instinct to make the error message more user friendly is a good one.
There's no reason you can't return a nicely formatted 404 page with your response. The status code could be the same, just the rendering is more user friendly than your typical 404 page. You could even return the "redirected" page in the response body. One possible problem with this is browser support. It's been quite a few years but I seem to recall IE (6?) completely disregarding response body content when receiving a 404. You'll have to experiment to see what works best for you.
I was thinking about the security aspect of the response provided to the client. If you get 204 you understand that the resource did exist but on 404 you can tell there is no such resource.
Not sure though how this can be exploited.
精彩评论