HABTM Checkboxes

August 3, 2007

When working with Rails, one of the 2 methods for dealing with many-to-many relationships is "Has and Belongs to Many" (HABTM). Despite it's declining popularity, I'm still under the belief that HABTM is still a viable choice if you just have a simple assocation between 2 models. Of course, that opinion is subject to change.

So until we've figured out how to full get rid of HABTM with "Has Many Through", we'll need to be creating interfaces to allow users to choose a set of models to associate to another model. One common way of doing this is using checkboxes, as is so eloquently explained in Railscast 17: HABTM Checkboxes.

One gotcha that pops up when dealing with a HABTM, as is pointed out in the Railscast, occurs when you are editing a model, and you want to remove all of the associations, in other words, remove a certain product from all categories. Because of the way HTML and HTTP works, if you uncheck all of the check boxes, no parameters get sent in the HTTP request at all. The Rails model and controller interpret the lack of parameters to mean "you don't want to change that value at all", so instead of removing all the categories for the product, the set of categories a product is in doesn't change at all.

The suggested work around for this in the Railscast is to add this following code to you controller:

params[:product][:category_ids] ||= []

This will initialize the category_ids array to an empty array if it doesn't exist. This works, but modifying the params in the controller could be considered dubious. A co-worker of mine pointed out an alternative to me today that I think is cleaner. Instead of putting the above code in your controller, you could put this code in the view:

<!-- products/_form.rhtml -->
<%= hidden_field_tag "product[category_ids][]", "" %>
<% for category in Category.find(:all) %>
<div>
    <%= check_box_tag "product[category_ids][]", 
        category.id, @product.categories.include?(category) %>
    <%= category.name %>
</div>
<% end %>

The 2nd line, the first one after the comment, is the only one added. That will send an empty string, which Rails will add to the array in the params, but then will be happily ignored by the model. The result is that the category_ids array in the params will never be nil, so no additional code is needed in the controller.

Posted in Technology | Tags Checkboxes, Rails, Ruby, HABTM

Comments Comments Feed

1. Ahoy,

I have a solution for has_many associations (therefore for habtm too) with a single select box and a list of checkboxes to store the associations.

It uses client-side javascript, no AJAX, and the code is simpler than Ryan Bates'complex forms.


Take a look at: http://clair.ro/rc/2008/10/13/has_many-with-select-box-and-checkboxes/

# Posted By cs on Monday, October 13 2008 at 10:35 AM

2. Have you found any new elegant way of doing this?

# Posted By Rex on Sunday, February 22 2009 at 9:03 PM

Add a Comment

(If you leave this blank, your IP address will be displayed instead)

(Optional, will not be displayed on the site)