Unobtrusive deleting with Rails and jQuery

Posted by andy gaskell on Nov 15th, 2009

I’m going to cover creating a sample Rails application, taking a look at how destroy works by default and how we can improve accessibility by writing unobtrusive JavaScript using the jQuery library.

First let’s create a new Rails application. We’ll call it ajaxstore.

Now let’s create some scaffolding and take a look at how it works.

Launch your favorite toob surfer to http://localhost:3000/products and create a few products to use. Back at the products list let’s take a look at the Destroy links. From a user’s perspective if you have JavaScript enabled you’ll get a confirmation dialog. If the user has JavaScript disabled he will be brought to the show action, and probably feel a little lost. From a developer standpoint there’s a lot of unnecessary repeated JavaScript on the Destroy links. Let’s get this fixed.

Let’s remove the default JavaScript that Rails adds to our project since we’re going to use jQuery.

Now let’s download jQuery.

Open up routes.rb – we need to add an option to the products resource route. I’m using delete as my option. You could overload destroy but in my opinion that makes the destroy action less cohesive.

We now need to add a view for our new action. Create a new file named ‘delete.html.erb’ in your product views directory. We’ll keep it fairly simple, and ask the user to confirm the destroy.

At this point we need to do some refactoring. Open up the Products controller and look at all the places we’re calling Product.find(params[:id]). We’re going to refactor that into a before filter and simplify the controller a bit. Here’s the entire controller.

Here we removed the edit and show actions, removed the first line from the update and destroy actions, created a method to load the product, and finally setup the filter. Now lets change how we generate our destroy links in the index and show views. First open up the Product index view and change the destroy link (should be around line 15) to this.

We’ll use the delete class in our JavaScript to handle delete clicks. For the show view, just remove the destroy link altogether. Browse to http://localhost:3000/products and create a product if need be, and now if you click on the “Delete” link we are brought to our delete view and our non-JavaScripting friends want to give us high fives. For the rest of our users, navigating to a new page is a bit much for deleting a product. Open up the layout file and add this under the stylesheet_link_tag.

We’re creating a AUTH_TOKEN variable so that when we make a POST, PUT or DELETE via ajax we can pass along the authentication token. Let’s add some jQuery code to application.js to handle deletions. This JavaScript has been pulled from a larger application so some parts of are maybe a little too industrial strength for a blog post, but I’m going to focus on the Rails side and less on the jQuery. If there’s enough demand to go into details on the jQuery we’ll talk more about it – the main points are the ajaxSend handler and the a.delete click handler.

We also need to make some changes to our CSS file – here are the styles we need to add.

Let’s get Rails setup to do some ajax’n. There are a couple changes you need to make to every application. Add these lines under the protect_from_forgery line in your application controller.

And under those lines add the corresponding methods:

The set_xhr_flash method removes the flash if the current request is an ajax request. If we don’t clear the flash on an ajax request the next time the user makes a full http request the user will see the flash message. The other method is for safari and IE browsers – we’re correcting some headers for ajax requests. One last change to our destroy action in our Products controller and we’re good to go.

Start up your browser and server if need be. We are now fully web 2.0. JavaScripters and NonJavaScripters can use our app equally and that makes us totally rad web folks. You can download the full project over at github.

undefined method ‘guard_condition’ when using subdomain_fu on Rails 2.2

Posted by andy gaskell on Dec 31st, 2008

frank and charlieWhile working with subdomain_fu I was having some issues with routes and it was suggested in the railscasts comments that installing from the plugin was different than the gem.

keyJ says:

I found that I makes a difference whether you install it as a plugin (from github) or a gem. With the gem I could not get the route to accept the :subdomain-condition correctly. But then I installed the plugin with ./script/plugin install…
and all of a sudden it worked fine.

This got me a step closer. When I restarted Apache I got this error message:
undefined method `guard_condition' for class `ActionController::Routing::Optimisation::PositionalArgumentsWithAdditionalParams'

I eventually figured out that this code was added a couple months ago – I removed the code referenced in the blog post and now my routing issues are resolved.

Rails helper distance_of_time_in_words ported to C#

Posted by andy gaskell on Sep 29th, 2008

kabouter can scale.While learning rails I came across a very cool helper method called distance_of_time_in_words. You’ve probably seen this method in action if you’ve used Twitter – no guessing about time zones and as a user I think it’s a nice touch. So on to the port itself…

The Good
C# is automatically faster because everyone knows Ruby is slow and that rails can’t scale.
Seriously though, the port to C# uses resource files so internationalization is handled by simply adding a translated resource file to your project.

The Bad
C# doesn’t have the concept of static extension methods. To me DateTime.DistanceOfTimeInWords would be much nicer than DateHelper.DistanceOfTimeInWords.
Range support in the language is hokey at best. No ranges in switch statements. bleh.

The Ugly
The code! If you compare the C# version to the Ruby version it’s a little ahhhhhhhhhhh… inelegant? The Ruby version weighs in at 28 lines of readable code. The C# version is a b-e-a-s-t with 55 lines of code including 2 helper methods. I’m open to any suggestions in making the C# code shorter or more readable.

The Rest
The method time_ago_in_words has also been ported. Altogether the helper code is 74 lines – also included is over 250 lines of test code. All examples listed on the Rails page were also included in the test.

You can grab the code here or at the subversion repository http://svn.gaskell.org/helpers