Wednesday, June 17, 2009

multiple actions using context menus in rails application

Context menus for a web application ? I know I am not a big fan for context menus either, but if somebody wants it bad you have to put them in, besides it depends on the website's scope.

So all the rails developers are familiar with the scaffold generated tables, with show, edit, delete actions as links to each row.

Now recently Ryan Bates updated his railscasts with multiple edits, which deals with how to edit and update common fields of a two or more "resources" at a time.

And I use redmine as a productivity tool and they have a cool (but very non intuitive) feature of a context menu through which you could do the same, like edit two issues, or change priority of those issues etc.

So here's what I did to get that redmine's context menu functionality with as little pain as possible.

Jquery's context menu plugin + Ryan Bates' multiple edits
and you get

to accomplish above
step 1: Wrap your table in form which posts to a special RESTful action in this case i called it multiple_actions in your template file and put a check_box field before each row. (see Ryan's scre

form_tag multiple_actions_banners_path, :id => 'multiple_actions'

step 2: configure this route in routes.rb

map.resources messages, :collection => {:multiple_actions => :post}

step 3: Define the action in your controller.rb file


  def multiple_actions
unless params[:message_ids].blank?
@banners = Message.find(params[:message_ids])
end
case
when params[:revoke]
revoke_multiple(@messages)
flash[:notice] = "Revoked #{@messages.count} Messages
......
else
end
respond_to do |format|
format.html {redirect_to(messages_path)}
end
end



step 4: Now for javascript , using guide lines from jquery context menu


function initializeContextMenu()
{
jQuery("table.listview tr td").contextMenu({
menu: 'myMenu'
},
function(action, el, pos) {
switch(action){
case 'revoke':
form_submit(action);
break;
case 'clone':
form_submit(action);
break;
case 'delete':
form_submit(action);
break;
case 'destroy':
form_submit(action);
break;
default :;
}
}
);
}

function form_submit(action)
{
if(jQuery("input:checked").length > 1) {
if(confirm("This action will impact multiple messages. Are you sure?")){
jQuery("#submit_type").append(jQuery("<input type='hidden' name='" + action +"'></input>"));
jQuery("form#multiple_actions").submit();
}
}
else {
alert('Select at least one item.');
}

}


Thats it that got me a minimal context menu capability.

Please understand that context menu is mostly eye-candy, because its not very intuitive and not the first thing a user would think of doing in a web browser.
It would be rather more useful if along with context menu we add buttons like in Gmail labs features for "Mark as Read" or "Delete" buttons, that would be very helpful for regular users.

Thursday, June 4, 2009

habtm based javascript UI in rails

From the time I have begun web-development in rails it has always been a big struggle to get Models and Views to play well together.
Few examples being, Restricting Views Based on Roles, Search forms in views.

Of course these days with ruby gems like Declarative Authorization , Authlogic, and Searchlogic life is not the same.

Still, as things get complex more, it gets really difficult to create user interfaces to powerfully play with models while following the programming style that rails encourages.
Forget about good CSS looks and Javascript Effects but also coming up with design which flows properly with the web application.

Okay now coming to the point of my rant.
Just today I have finished designing and developing UI which took quite a bit of ruby, javascript and rjs, but in the end was worth it, without having to put in a lot of javascript (unobtrusive or not), and not ending up writing something from scratch.

So here's the problem, there are two models with habtm relationship (dont ask why), now we know the traditional form with either
  1. checkboxes or
  2. collection_select in the form ,
  3. also I came across another solution which was just as I wanted with option transfer select boxes called SwapSelect.
Which was kind of cool, but it was limited in certain things for example, it needed all the options in to construct a big select box, and javascript code was beyond my understanding of javascript or simply put the author did not use any JS library , he wrote the traditional javascript which I am not comfortable coding in.

ok now I wanted the following
  1. A select box on the left with filters to list by name keywords, display only 25 records and then display additional by pagination etc.
  2. A second select box on the right which displays existing options and acts like a container for adding new options from the one on the left.
  3. and buttons in between to add selected to right, add selected to left, add all to right and add all to left options.
Like the following picture

ok the first point a search enabled list of available options was actually the easiest part, this is where I used Searchlogic, which is a brilliant rubygem, now other than that everything was simple javascript using Prototype library, rjs and little ruby.

What happens after the options are final is that I clone the final select box and give it a new name with _ids[] in the end folowing rails convention to make a habtm form object which I attach it to the model's form. and the voila the record updated with a put or created with a post following REST.

The way rails architecture allows you to design this kind of complex simply is what inspired "Me" to write about it.

Update:
Soon as I published I saw another article which is very good, and its a plugin too.