Archive for November, 2007

h1

NestedSortable Rails Plugin

November 19, 2007

If you are a Ruby on Rails developer (if not you should become one) I have good news for you: a Rails plugin that makes it really easy to implement a NestedSortable Widget data source is almost ready for primetime. That will make implementing the NestedSortable Widget as easy as 1-2-3. It is already working, as a matter of fact, its only missing some automated tests, helpers I want to create (for including the NestedSortable widget in your views) and documentation. It works for Rails 1.2.3, I haven’t tested it with Rails edge yet.

I will give a brief overview of how it works. All you need is a model with a column that should hold a foreign key to the parent and a column to hold an index number for the position of the element inside its hierarchy. The defaults (convention over configuration!) are “parent_id” and “position”. Suppose our model (the one we want to nest and sort) is named “Item”. You will only need one line of code to implement a data source for it in your controller:

class ItemsController < ApplicationController
	nested_sortable_data_source_for :item
end

By default the data source will be created under an action named “order”, inside your controller. Don’t worry, all the defaults can be overridden (wait for the docs or take a peak at the code).

In your view, it will be pretty easy to add the NestedSortable Widget, as always:

<script> 	
	jQuery( function($) {
		$('#items_sort').NestedSortableWidget({
 			loadUrl: "/items/order/1.json"
 		});
	});
</script> 
<div id="items_sort"></div>

Don’t forget that you will need to include the scripts (jQuery, Interface, etc) and the CSS file for the widget, by putting something like this in the HEAD of your HTML file, in your layout file probably:

<%= stylesheet_link_tag 'ns/nestedsortablewidget' %>
<%= javascript_include_tag "jquery-1.1.4.js" %>
<%= javascript_include_tag "interface-1.2.js" %>
<%= javascript_include_tag "inestedsortable-1.0.1.pack.js" %>
<%= javascript_include_tag "jquery.nestedsortablewidget-1.0.pack.js" %>

Ok, you say. That is neat, but how do I customize what data will be displayed in the columns by my NestedSortable Widget? The default is to display all the columns/attributes your model has (excluding the ID and foreign keys). You can use the :columns option of the nested_sortable_data_source_for to make your data source display pretty much anything you want, in any order you want. Just an example:

nested_sortable_data_source_for(
	:item,
	:columns=>[
		[:title, 'Title of the Item'],
		[:description, 'Description of the Item'],
		[ lambda {|i| i.created_at.to_date.to_formatted_s(:long)}, 'Creation Date'],
		[ lambda {|i| i.attachments.count}, 'Attachments']
	]
)

If you are smart enough you already got it: it will display a table with 4 columns, the title of the item, description, creation date and the number of attachments it has. Note the use of lambdas (functions that are passed as variables). It gives you the power to display whatever you want in the columns of your NestedSortable Widget.

Ok again, you say. The way things are until now will only allow me to have one set of items per database table. In your application, you will usually have a lot of users, and will not want to create one table per user. You want everything in the same table, and your “item” model probably have a “user_id” foreign key. That has been thought of as well. You have the :conditions option, which will give you the flexibility you need. An example:

nested_sortable_data_source_for(
	:item,
	:conditions=> lambda {|controller| {:user_id => controller.params[:id]} }
)

Note the funky lambdas again. Instead of a lambda, you may pass in a symbol, like :conditions_generator with the name of a method in your controller (make it protected, please) that will generate the conditions for you. The conditions are exactly like the ones you may use in your finders in Rails: they may be strings with SQL, they may be arrays like [“a = ?”, “b”], and anything else that is allowed in Rails conditions.

In your view, in the part you set up the widget, you would probably use something like:

loadUrl: "/items/order/<%=current_user.id%>.json"

This is insecure: users could easily change the order of the items that belong to other users, with little effort. To implement security, you need to make our condition generator a little bit smarter. It is up to you, though…

Briefly, that is what this plugin for Rails does: it makes it ridiculously easy to implement a NestedSortable Widget in your Rails apps (I bet you could do it in 5 minutes!). Don’t show it to your boss, he will probably fire you and begin doing it himself. Note that the data source you create fully supports pagination: you may use any option the NestedSortable Widget provides and it should work like a charm.

To try the plugin, install it using Rails install command, in your Rails application path:

script/plugin install https://nestedsortables.googlecode.com/svn/trunk/rails/nested_sortable

Advertisements