您还必须将CategoryProduct添加到每个模型:
我是编程和Rails的新手,有些事情我还不太了解。我正在使用
创建一个应用product has_many categories
category has_many products
如果我理解正确,我需要创建一个具有product_id
和category_id
的联接表products_categories。首先,我还需要该表的模型吗?如果是的话,我想它将看起来像这样:
class CategoryProduct < ActiveRecord::Base
belongs_to :category
belongs_to :product
end
和product.rb中的其他模型:
class Product < ActiveRecord::Base
has_many :category_products
has_many :categories, through: :category_product
has_attached_file :picture,
styles: { medium: "300x300>", thumb: "100x100>" }
validates_attachment_content_type :picture,
content_type: /\Aimage\/.*\z/
validates :price, presence: { message: "Merci d'indiquer le prix du produit" }
validates :name, presence: { message: "Merci d'indiquer le nom du produit" }
validates :weight, presence: { message: "Merci d'indiquer le poids du produit" }
validates :description, presence: { message: "Merci d'écrire une description du produit " }
end
和category.rb
class Category < ActiveRecord::Base
has_many :category_products
has_many :products, through: :category_product
validates :name, presence: { message: "Merci d'indiquer le nom de la catégorie" }
end
现在假设我要创建一个产品,并且在创建产品时,请从类别列表中为该产品指定尽可能多的类别。
到目前为止,我认为这是我的Product / new.html.slim:
div class="container marged-top"
div class= "col-xs-12 col-md-offset-3 col-md-5 bigmarge"
div class="panel panel-default"
div class= "panel-heading"
h4 Création Produit
div class= "panel-body"
=simple_form_for @product, html: { multipart: true } do |t|
= t.error_notification
= t.input :name, label: 'Nom'
= t.input :description, label: 'Description', required: true
= t.input :price, label: 'Prix', required: true
= t.input :weight, label: 'Poids', required: true
= t.label :picture
= t.file_field :picture
= t.association :categories, as: :check_boxes
= t.button :submit, value: "Valider", class: "btn-success marge-bas"
这是我的Product实例的简单表格。我想我现在需要一个CategoryProduct的表格吗?如果我希望用户在创建产品时能够向产品添加任意数量的类别,我该如何更改?
这是我用于category_product表的迁移文件:
类CreateTableCategoriesProducts 我使用以下迁移文件重命名了上一个表: 我在product / new.html.slim中的simple_form上收到以下错误: 代码在这里中断: 所以我想我的协会至今还算不错 def change
create_table :categories_products do |t|
t.references :product, index: true
t.references :category, index: true
end
add_foreign_key :categories_products, :categories
add_foreign_key :categories_products, :products
end
end
class RenameTableCategoriesProducts < ActiveRecord::Migration
def self.up
rename_table :categories_products, :category_products
end
def self.down
rename_table :category_products, :categories_products
end
end
undefined method `klass' for nil:NilClass
= t.association :categories, as: :check_boxes
在Rails中,有两种建立多对多关系的方法:
has_and_belongs_to_many
无需干预模型即可建立多对多关系。
class Category < ActiveRecord::Base
has_and_belongs_to_many :products
end
class Product < ActiveRecord::Base
has_and_belongs_to_many :categories
end
如果您不需要存储有关该关系的任何其他数据或添加任何其他功能-这在实践中实际上很少见,那么这是一个不错的选择。它使用较少的内存,因为它不必仅为了执行product.category
就实例化一个额外的模型。
[使用has_and_belongs_to_many
时的惯例是,联接表以两个实体复数命名。按制造顺序:
Category + Product = products_categories
has_many through
您已经猜到使用中间模型。
class CategoryProduct < ActiveRecord::Base belongs_to :product belongs_to :category end class Category < ActiveRecord::Base has_many :category_products has_many :products, through: :category_products end class Product < ActiveRecord::Base has_many :category_products has_many :categories, through: :category_products end
这里的优点是,您可以在描述关系的联接表中存储和检索其他数据。例如,如果您想存储将产品添加到类别的人员-或创建关系的时间。
为了使Rails能够正确找到ProductCategory类,has_many though
命名约定的连接表是
model 1(singular) + model 2(plural) Product + Category = category_products
这是由于rails根据表名推断模型类的方式。使用
categories_products
将使rails查找Category::CategoriesProduct
。
正如IvanSelivanov已经提到的,SimpleForm具有用于创建选择,复选框等的辅助方法。>
但是您可能不想使用模型中的.to_s
方法,而是要使用label_method选项。
f.assocation :categories, as: :checkboxes, label_method: :name
覆盖
.to_s
会使调试更加困难,并且在某些情况下会给出令人困惑的测试错误消息。要在控制器中将参数列入白名单,您可以这样做:
class ProductsController < ApplicationController
def create
@product = Product.new(product_params)
if @product.save
redirect_to @product
else
render :new
end
end
def product_params
params.require(:product)
.permit(:name, :categories_ids, ...)
end
end
您还必须将CategoryProduct添加到每个模型:
class Product < ActiveRecord::Base
has_many :category_products
has_many :categories, through: :category_product
使用宝石simple form
非常简单。您所要做的就是添加:
t.association :categories
以产品的形式并将:category_ids => []
添加到产品控制器中允许的参数列表中
如果您希望使用复选框而不是多选列表,则可以
t.association :categories, as: check_boxes
最后,要以人类可读的格式显示类别,您需要在类别模型中定义
to_s
方法,即e。:class Category < ActiveRecord::Base ... def to_s name end end
您还必须将CategoryProduct添加到每个模型: