Ruby on rails Rails中的多个连接表

Ruby on rails Rails中的多个连接表,ruby-on-rails,forms,model,jointable,Ruby On Rails,Forms,Model,Jointable,我是编程和rails新手,有一点我不完全理解。 我正在使用创建一个应用程序 product has_many categories category has_many products 如果我理解正确,我需要创建一个联接表products\u categories,该表具有product\u id&一个category\u id。首先,我还需要这张桌子的模型吗?如果是,我猜会是这样: class CategoryProduct < ActiveRecord::Base belong

我是编程和rails新手,有一点我不完全理解。 我正在使用创建一个应用程序

product has_many categories
category has_many products
如果我理解正确,我需要创建一个联接表products\u categories,该表具有
product\u id
&一个
category\u id
。首先,我还需要这张桌子的模型吗?如果是,我猜会是这样:

class CategoryProduct < ActiveRecord::Base
   belongs_to :category
   belongs_to :product
end
这是我的产品实例的一个简单表单。我想我现在需要一个类别产品的表格? 如果我希望用户在创建产品时能够向产品添加他想要的任意多个类别,那么我必须如何改变这一点

这是我的category_产品表迁移文件:

类CreateTableCategoriesProducts
  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
代码在此中断:

 = t.association :categories, as: :check_boxes

因此,我想我的关联仍然不太正确

您还必须将CategoryProduct添加到每个模型中:

class Product < ActiveRecord::Base
  has_many :category_products
  has_many :categories, through: :category_product
在产品的表单中,并将
:category_id=>[]
添加到产品控制器中允许的参数列表中

如果您喜欢复选框而不是多选列表,您可以这样做

    t.association :categories, as: check_boxes
最后一件事,要以人类可读的格式显示类别,您需要在类别模型中定义一个
to_s
方法,即。e、 :

class Category < ActiveRecord::Base
  ...
  def to_s
    name
  end 
end
类别
在Rails中,有两种方法可以处理多对多关系:

你和你属于很多人吗 在没有干预模型的情况下建立多对多关系

class Category < ActiveRecord::Base
  has_and_belongs_to_many :products
end

class Product < ActiveRecord::Base
  has_and_belongs_to_many :categories
end
顺序似乎无关紧要

你通过以下途径获得了很多好处: 正如您已经猜到的,使用中间模型

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基于表名推断模型类的方式造成的。使用
categories\u products
将使rails查找
Category::CategoriesProduct
,因为复数词被解释为模块。然而,这实际上只是一种惰性命名约定,通常有一个名词可以更好地描述a和B之间的关系(例如
分类

表单和控制器中的多对多。 正如IvanSelivanov已经提到的,SimpleForm具有用于创建选择、复选框等的帮助器方法

但是,您可能需要使用label\u method选项,而不是覆盖模型中的
.to\s
方法

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
class ProductsController
我按照你说的做了,但是当我将t.association:category添加到我的产品/new.html.slim表单时;我得到以下错误:Association:category not found
t.Association:categories
@max现在我得到了nil的未定义方法“klass”:NilClass@IvanSelivanov我也不明白为什么在你的协会里你写的
有很多:类别产品
,为什么不
:categories\u products
?@Dave这是因为我认为这是CategoryProduct的正确复数形式。您是否将
has\u和\u belient\u to \u many
更改为
has\u many
?如果您发布相应的代码(错误消息中通常有行号),则更容易判断错误的含义。有关如何修复联接表的表名,请参阅。感谢您的回答,我知道我的产品简单表单中出现错误。当点击行:=t.association:categories,as::复选框时,代码以简单形式中断。可能是因为我在迁移文件中命名表的方式:
:categories\u products
应该是
categories\u products
如果我遵循youNP,是的,我猜这就是问题所在。但是一个很好的技巧是要比“获取错误”更具体一点-如果包含错误消息,帮助会容易得多。nope事件在更改表名后,我仍然会在第16行的简单表单中为nil:NilClass`获取
undefined method
klass'=t.association:categories,as::复选框`添加
debug@product.categories
会给您带来什么?
class Category < ActiveRecord::Base
  ...
  def to_s
    name
  end 
end
class Category < ActiveRecord::Base
  has_and_belongs_to_many :products
end

class Product < ActiveRecord::Base
  has_and_belongs_to_many :categories
end
Category + Product = products_categories
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
model 1(singular) + model 2(plural) 
Product + Category = category_products
f.assocation :categories, as: :checkboxes, label_method: :name
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