在很多情况下,会遇到表的多对多关系,例如套餐和产品,一个套餐拥有多个产品,而一个产品又可以属于多个套餐,那么在编辑套餐时,你可能会用checkbox,列出所有的产品,供其选择,下面就通过实例来实现这个应用:
①、Model里设计关系
class Package< ActiveRecord::Base
has_and_belongs_to_many :products
end
class Product < ActiveRecord::Base
has_and_belongs_to_many :packages
end
②、手工建表packages_products
+---------------- +--------- +------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------- +--------- +------+-----+---------+-------+
| package_id | int(11) | NO | MUL | NULL | |
| product_id | int(11) | NO | MUL | NULL | |
| product_amount | int(11) | NO | | 1 | |
| options | int(11) | YES | | NULL | |
+-----------------+----------+------+-----+---------+-------+
补充:多对多关系的另一种定义方法:关键字 :through
class PackProduct< ActiveRecord::Base
belongs_to :product
belongs_to :package
end
class Package< ActiveRecord::Base
has_many :pack_products
has_many :products, :through =>:pack_products
end
class Product < ActiveRecord::Base
has_many :pack_products
has_many :packages, :through =>:pack_products
end
③、在packages的edit视图里显示checkbox
%table{:border=> '0'}
- i = 0
- for product in Product.find( :all )
- if i % 9 == 0
%tr
%td
= check_box_tag "package[product_ids][ ]",
product.id, @package.products.include?(product)
= link_to product.name , product
- i = i+1
注:这里首先是用了Haml模板,所以蓝色部分最好写成一行,其次为了让每行(%tr)只显示10个选项,用了个比较笨的方法,就是计数器 i 。最后,看到 product_ids属性是package的has_and_belongs_to_many自动生成的 。
④、 修改PackageController的update方法
def update
params[:package][:product_ids] ||= [ ]
@package = Package.find(params[:id])
.....................
end
注意:update方法需要先使用params[:product][:product_ids] ||= [ ]来将product_ids清空不然当我们取消所有的productCheckbox时,后台sql不会传递空的product_ids数组,而是不传递product_ids参数这样会导致取消不了productCheckbox。