(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