(this code is also at http://rafb.net/paste/results/KPgNpg49.txt ) # This code is sort of cool, I think. Too bad that I have to write it for habtm. # # This is a fairly easy way to let users edit a habtm relationship with # checkboxes. # # Following is the relevant code for a Product that habtm Categories, Artists, # Authors, and publishers. # in views/products/_form.rhtml: <%= product_habtm_selector Category, @product %> <%= product_habtm_selector Artist, @product %> <%= product_habtm_selector Author, @product %> <%= product_habtm_selector Publisher,@product %> # in a helper: # Creates a table that has checkboxes for a habtm relationship # with a product. def product_habtm_selector klass, product cols = 3 count = 0 result = "#{ klass.to_s.pluralize } <br />" result << "<table>" klass.find(:all).each do |thing| result << "<tr>" if count % rows == 0 result << "<td valign=''top''>" result << "<label for=''#{ thing.name }''>" result << check_box_tag("product[#{ klass.to_s.pluralize.downcase }_ids][]", thing.id, product.send("has_#{ klass.to_s.downcase }?", thing.id)) result << thing.name result << "</label>" result << "</td>" result << "</tr>" if count % cols == (count - 1) count += 1 end result << "</table>" result end # Extending active record with a couple methods. class ActiveRecord::Base def self.define_habtm_setter(the_many) module_eval <<-CODE def #{the_many}_ids=(ids) #{the_many}.clear for id in ids if id.respond_to? :read #{the_many} << #{the_many.to_s.classify}.find(id.read) else #{the_many} << #{the_many.to_s.classify}.find(id) end end end validates_associated :#{the_many} def has_#{the_many.to_s.singularize}?(id) #{the_many}.to_a.find {|a| a.id == id} end CODE end # Models: class Product < ActiveRecord::Base has_and_belongs_to_many :categories define_habtm_setter :categories has_and_belongs_to_many :authors define_habtm_setter :authors has_and_belongs_to_many :artists define_habtm_setter :artists has_and_belongs_to_many :publishers define_habtm_setter :publishers ... end class Publisher < ActiveRecord::Base has_and_belongs_to_many :products end # and Artists, Authors, and Categories are the same as Publisher. # ProductsController#update # If no checkboxes are in params, then the user has deselected all checkboxes. def update @product = Product.find(params[:id]) if @product.update_attributes(params[:product]) if params[:product][:categories_ids].nil?; @product.categories.clear; end if params[:product][:authors_ids].nil?; @product.authors.clear; end if params[:product][:artists_ids].nil?; @product.artists.clear; end if params[:product][:publishers_ids].nil?; @product.publishers.clear; end ... end