【问题标题】:Rails HABTM setup, model object, & join_table insertion controller setupRails HABTM 设置、模型对象和连接表插入控制器设置
【发布时间】:2026-01-25 21:45:02
【问题描述】:

我有以下设置。

1 个产品有许多 product_types。 许多 product_types 有 1 种类型。 根据我对文档的理解,HABTM 关系。

我的模型是

class Product < ApplicationRecord
  has_and_belongs_to_many :types
end

class Type < ApplicationRecord
  has_and_belongs_to_many :products
end

我有一个这样的连接表迁移

class CreateJoinTableProductTypes < ActiveRecord::Migration[5.1]
  def change
    create_join_table :products, :types do |t|
      t.index :product_id
      t.index :type_id
    end
  end
end

我已经创建了一个表单 - 希望可以正确创建,现在我在表单提交时发送了以下参数:

"product"=>{"name"=>"Product A", "description"=>"A cool product", "image_dir_path"=>"./",
"type"=>{"id"=>"1"}},"commit"=>"Create Product"}

我想知道 1) 在表单和控制器中提交用于创建产品的参数的最佳/rails 约定是什么?

2) 我如何/如何获得插入连接表的记录?

我有以下获取参数的方法

def product_params
  params.require(:product).permit(:name, :description, :image_dir_path, :type,)
end

但即便如此,我也可以在日志中看到 :type 的 unpermitted 参数

目前我的控制器只有:

@product = Product.new(product_params)

我将非常感谢有关创建此对象的 rails 方式的任何建议。我已经阅读了 HABTM 的 api 文档,但没有看到任何关于模型对象或我应该如何在控制器中处理这些东西的内容。

谢谢!

【问题讨论】:

  • 产品中没有type。你有很多类型。您可以将type_ids: [ ] 添加到product_params.,这是一个类型id 的数组。

标签: ruby-on-rails model controller has-and-belongs-to-many jointable


【解决方案1】:

ActieRecord 为所有 has_manyhas_and_belongs_to_many 关联生成 _ids setter 和 getter。

# creates 3 rows in products_types if they do not exist
# also deletes any rows not in the array
@product.update(type_ids: [1,2,3])

这些与form options helpers 一起使用来分配关联:

<%= form_for(@product) do |f| %>
  <div class="field">
    <%= f.label :type_ids %>
    <%= f.collection_select :type_ids, Type.all, :id, :name, multiple: true %>
  </div>
  ...
<% end %>

要将参数列入白名单,请将其作为选项传递,其值为 [],它允许包含任何标量类型的数组。

def product_params
  params.require(:product).permit(:name, :description, :image_dir_path, type_ids: [])
end

2) 我如何/如何获得插入连接表的记录?

使用has_and_belongs_to_many 关联,您只能间接插入/访问行。

例如:

@product.types 
# or
@product.types << Type.first
# or
@product.types.create(name: 'Foo')

或者使用前面提到的type_ids setter/getter。这是与 has_many through: 的关键区别,在 has_many through: 中,您有一个可以直接查询或创建的连接模型。

【讨论】:

  • 谢谢,我会在今天晚些时候试试这个。不过似乎有道理! :)
  • 没有完全回答我的问题。发布此消息后,我发现我的模型类型实际上是一对多的关系。但我将上述内容应用于另一种型号的产品和尺寸。我尽量遵守约定,最终对它的工作方式感到满意
【解决方案2】:

在 max 的评论之后,我意识到类型关系不是 HABTM,而是与产品的一对多关系。不过,我有另一个模型 Size,它位于带有 Product 的 HABTM 中。

我的模型如下所示:

class Product < ApplicationRecord
  belongs_to :product_type
  has_and_belongs_to_many :sizes
end

class Size < ApplicationRecord
  has_and_belongs_to_many :products
end

连接表是:

class CreateJoinTableProductSize < ActiveRecord::Migration[5.1]
  def change
    create_join_table :cakes, :sizes do |t|
      t.index [:product_id, :size_id]
    end
  end
end

尺寸表是默认的 产品表是

class CreateProducts < ActiveRecord::Migration[5.1]
  def change
    create_table :products do |t|
      t.string :name
      t.string :description
      t.references :product_type, foreign_key: true

      t.timestamps
    end
  end
end

我的控制器是默认的 - 我只是将以下参数列入白名单

def cake_params params.require(:product).permit(:name, :description, :product_type_id, {:size_ids=>[]}) 结束

我的 _form 有以下内容

  <div class="field">
    <%= form.label :product_type_id %>
    <%= form.collection_select(:product_type_id, ProductType.all, :id, :name) %>
  </div>

  <div class="field">
    <%= form.label :product_size %>
    <%= collection_check_boxes(:product, :size_ids, Size.all, :id, :name) %>
  </div>

现在我可以提交表单,对其进行编辑,所有值都会正确显示!

【讨论】:

  • 非常感谢,这是我在 rails 5 中使用 habtm udpate 和创建的唯一解决方案:= f.collection_select(:category_ids, @help_desk.categories, :id, :title) 请请注意,在这种情况下,您必须将关联模型的请求参数列入白名单 category_ids