Merb CRUD - ie: how to properly destroy things
By now most Rails developers have come to know and love (or not?) RESTful resources and the controller code that implements them. For the most part Merb’s implementation of resources will be familiar and adheres to the same convention - GET safe creates, updates, destroys, a single base URI for a single resource, etc.
One small difference with Merb’s resources is in regards to the implementation of destroying a resource. In Rails you run into this weird situation where performing a destroy on a record via a browser is nearly impossible without relying on Javascript to create that ugly dynamic form that gets triggered by using the link_to method and passing “:method => :delete”.
<%= link_to "Delete Image", { :action => "delete", :id => @image.id }, :confirm => "Are you sure?", :method => :delete %>
# => <a href="/testing/delete/9/" onclick="if (confirm('Are you sure?')) { var f = document.createElement('form');
f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;
var m = document.createElement('input'); m.setAttribute('type', 'hidden'); m.setAttribute('name', '_method');
m.setAttribute('value', 'delete'); f.appendChild(m);f.submit(); };return false;">Delete Image</a>
Not ideal IMHO.
The other option in Rails is to create the delete link manually as a button or submit tag in its own little form - personally i use this approach because it is does not require Javascript to work, but I have never liked cluttering the DOM with tons of little forms.
Merb, has a different answer - one that tripped me up until I realized what was going on: use an intermediary page.
In Merb a GET request to /users/1/delete (with the users resource declared in the router) will route to the “delete” method in the users controller. The purpose of this page is exactly the same as the “new” and “edit” methods - to provide an HTML form to someone (or something) interacting with the resource via a web browser. The idea is that in a non-Javascript world you can still implement an “are you sure?” type confirmation AND get the added benefit of providing a GET safe destroy. If the developer would like to mimic the Rails inline javascript delete form style html link it is trivial to do so, but with the added benefit of graceful degradation (ie: still works without javascript).
The ideal solution in my humble opinion is first implement the full delete page with destroy html form and “Are you sure?” confirmation message and then after that is working (and tested). Next you would implement an Ajax destroy button that posts a DELETE request and will be routed directly to the destroy method in the controller. This way you get a great user experience when using a fully featured web browser, but are still able to use the app if you happen to not have javascript.
Trackbacks
Use this link to trackback from your own site.
I like the idea of graceful degradation. If you are committed to making your entire app designed to be fully functional without javascript and you happen to have some extra time and determination to be sure everything degrades gracefully then go for it. For me, graceful degradation means one of three things: more work, limited coolness in UI, or both.
My main problem with the inline javascript approach is that it is obtrusive. I don’t like to pollute my HTML with inline script especially when that script is rendered repeatedly by a loop. Yuck.
+1 on what Sean was saying.
I agree whole heartedly with that. Plus the ease with which you can modify/override the delete action unobtrusively with Jquery etc makes it a no brainer in my book.
Sean I am not sure I follow you… what is your preferred solution for providing UI that results in the destruction of a record? And which framework are you talking about - Rails or Merb?
I prefer to have delete links to have a delete class that an unobtrusive javascript binds on dom:loaded. The delete links have the URL, but the binding onclick grabs the link and creates a confirmation and form to post a restful delete. I realize that this technique does not have a fall back for those without javascript enabled. However, I do believe that this deletion confirmation page that Merb creates would be a perfect fall back in the event that users did not have javascript enabled.
Our techniques are fairly similar, and I will more than likely start adding an interim confirmation page for the non-javascript enabled. The biggest need for having a non-javascript option is accessibility issues with screen readers. For projects, I try to find out from the client if they are willing to pay for me to include development for non-javascript enabled browsers.
Ah… yes… in fact I do exactly the same thing as far as unobtrusively binding to the anchor. I tend use an ajax call in place of injecting a form into the DOM though (since i already have a fallback page in place I can fully lean on javascript and avoid having to refresh the entire page). I didn’t go into great detail on that part of the implementation simply because I felt it was outside the scope of the article. Thanks for the comments guys!
Man…glad you posted that. I know you told this to me once, but it didn’t hit me that I needed to create the delete action to serve up my destroy page until I wanted the better delete solution.